Showing preview only (975K chars total). Download the full file or copy to clipboard to get everything.
Repository: pizzamig/pot
Branch: master
Commit: 5ef4db1cb181
Files: 189
Total size: 922.2 KB
Directory structure:
gitextract_cytad9_s/
├── .github/
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug_report.md
│ │ └── feature_request.md
│ └── workflows/
│ ├── ci.yml
│ ├── main.yml
│ └── shellcheck.yml
├── .gitignore
├── .travis.yml
├── CHANGELOG.md
├── Jenkinsfile
├── LICENSE
├── README.md
├── bin/
│ └── pot
├── etc/
│ ├── pot/
│ │ ├── flavours/
│ │ │ ├── dns
│ │ │ ├── dns.sh
│ │ │ ├── fbsd-update.sh
│ │ │ └── slim.sh
│ │ ├── pot.conf.sample
│ │ └── pot.default.conf
│ └── rc.d/
│ ├── pot
│ └── pot_early
├── release.sh
├── share/
│ ├── doc/
│ │ └── pot/
│ │ ├── .gitignore
│ │ ├── Description.md
│ │ ├── Images.md
│ │ ├── Installation.md
│ │ ├── Makefile
│ │ ├── QuickStart.md
│ │ ├── Synopsis.md
│ │ ├── conf.py
│ │ ├── index.md
│ │ └── migration.md
│ ├── pot/
│ │ ├── add-dep.sh
│ │ ├── clone-fscomp.sh
│ │ ├── clone.sh
│ │ ├── common-flv.sh
│ │ ├── common.sh
│ │ ├── config.sh
│ │ ├── copy-in.sh
│ │ ├── copy-out.sh
│ │ ├── create-base.sh
│ │ ├── create-fscomp.sh
│ │ ├── create-private-bridge.sh
│ │ ├── create.sh
│ │ ├── de-init.sh
│ │ ├── destroy.sh
│ │ ├── exec.sh
│ │ ├── export-ports.sh
│ │ ├── export.sh
│ │ ├── get-attribute.sh
│ │ ├── get-rss.sh
│ │ ├── help.sh
│ │ ├── import.sh
│ │ ├── info.sh
│ │ ├── init.sh
│ │ ├── last-run-stats.sh
│ │ ├── list.sh
│ │ ├── mount-in.sh
│ │ ├── mount-out.sh
│ │ ├── network.sh
│ │ ├── prepare.sh
│ │ ├── prune.sh
│ │ ├── ps.sh
│ │ ├── purge-snapshots.sh
│ │ ├── rename.sh
│ │ ├── revert.sh
│ │ ├── set-attribute.sh
│ │ ├── set-cmd.sh
│ │ ├── set-env.sh
│ │ ├── set-hook.sh
│ │ ├── set-hosts.sh
│ │ ├── set-rss.sh
│ │ ├── set-status.sh
│ │ ├── show.sh
│ │ ├── signal.sh
│ │ ├── snapshot.sh
│ │ ├── start.sh
│ │ ├── stop.sh
│ │ ├── term.sh
│ │ ├── top.sh
│ │ ├── update-config.sh
│ │ ├── version.sh
│ │ └── vnet-start.sh
│ └── zsh/
│ └── site-functions/
│ └── _pot
└── tests/
├── CI/
│ ├── resolv.conf-dual
│ ├── resolv.conf-ipv4
│ ├── resolv.conf-ipv6
│ └── run.sh
├── add-dep1.sh
├── clone-fscomp1.sh
├── clone1.sh
├── clone2.sh
├── common-flv1.sh
├── common-stub.sh
├── common-zfs1.sh
├── common-zfs2.sh
├── common1.sh
├── common2.sh
├── common4.sh
├── common5.sh
├── common6.sh
├── common7.sh
├── common8.sh
├── conf-stub.sh
├── config1.sh
├── copy-in1.sh
├── copy-out1.sh
├── create-base1.sh
├── create-fscomp1.sh
├── create-private-bridge1.sh
├── create1.sh
├── create2.sh
├── create3.sh
├── destroy1.sh
├── export-ports1.sh
├── export1.sh
├── get-rss1.sh
├── import1.sh
├── info1.sh
├── info2.sh
├── list1.sh
├── list2.sh
├── monitor.sh
├── mount-in1.sh
├── mount-out1.sh
├── network1.sh
├── pipefail-stub.sh
├── ps1.sh
├── rename1.sh
├── rename2.sh
├── rename3.sh
├── rename4.sh
├── revert1.sh
├── set-attr1.sh
├── set-attr2.sh
├── set-cmd1.sh
├── set-env1.sh
├── set-env2.sh
├── set-hook1.sh
├── set-hosts1.sh
├── set-rss1.sh
├── show1.sh
├── shunit/
│ ├── .gitignore
│ ├── .travis.yml
│ ├── CODE_OF_CONDUCT.md
│ ├── LICENSE
│ ├── README.md
│ ├── doc/
│ │ ├── CHANGES-2.1.md
│ │ ├── RELEASE_NOTES-2.1.0.txt
│ │ ├── RELEASE_NOTES-2.1.1.txt
│ │ ├── RELEASE_NOTES-2.1.2.txt
│ │ ├── RELEASE_NOTES-2.1.3.txt
│ │ ├── RELEASE_NOTES-2.1.4.txt
│ │ ├── RELEASE_NOTES-2.1.5.txt
│ │ ├── RELEASE_NOTES-2.1.6.txt
│ │ ├── RELEASE_NOTES-2.1.7.md
│ │ ├── TODO.txt
│ │ ├── contributors.md
│ │ └── design_doc.txt
│ ├── examples/
│ │ ├── equality_test.sh
│ │ ├── lineno_test.sh
│ │ ├── math.inc
│ │ ├── math_test.sh
│ │ ├── mkdir_test.sh
│ │ ├── mock_file.sh
│ │ ├── mock_file_test.sh
│ │ ├── party_test.sh
│ │ └── suite_test.sh
│ ├── lib/
│ │ ├── shflags
│ │ └── versions
│ ├── shunit2
│ ├── shunit2_args_test.sh
│ ├── shunit2_asserts_test.sh
│ ├── shunit2_failures_test.sh
│ ├── shunit2_macros_test.sh
│ ├── shunit2_misc_test.sh
│ ├── shunit2_standalone_test.sh
│ ├── shunit2_test_helpers
│ └── test_runner
├── signal1.sh
├── signal2.sh
├── snapshot1.sh
├── start2.sh
├── start3.sh
├── start4.sh
├── stop1.sh
├── term1.sh
├── test-suite.sh
├── top1.sh
└── version1.sh
================================================
FILE CONTENTS
================================================
================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: Bug report
about: Report a bug you found
title: "[BUG]"
labels: bug
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Create the `pot` with this command: '...'
2. Run this command: '...'
3. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**System configuration - if possible**
- `/usr/local/etc/pot/pot.conf`
** If network related **
- `cat /etc/pf.conf`
- `potnet show -v`
**Additional context**
Add any other context about the problem here.
================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.md
================================================
---
name: Feature request
about: A nice to have
title: ''
labels: feature
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the feature you'd like to have**
A clear and concise description of what you want to happen.
**Describe potential alternatives or workaround you've considered (if any)**
A clear and concise description of any alternative solutions or workaround you've considered.
================================================
FILE: .github/workflows/ci.yml
================================================
name: Run CI
on:
workflow_dispatch:
push:
branches: [ github-ci-action ]
# pull_request:
# branches: [ master ]
jobs:
ci_test_suite:
name: CI test suite
runs-on: ${{ matrix.job.os }}
strategy:
fail-fast: false
matrix:
job:
- { os: macos-12 }
release: [ "13.1" ]
steps:
- uses: actions/checkout@v3
- name: Run tests/CI/run.sh
uses: vmactions/freebsd-vm@v0
with:
mem: 8192
usesh: true
copyback: false
prepare: pkg install -y curl gmake potnet freebsd-release-manifests nmap
run: |
#####################################################################################
### Prepare, build, and test
#####################################################################################
### based on ref: <https://github.com/rust-lang/rustup/pull/2783>
### and on ref: <https://github.com/uutils/coreutils/commit/86c610a84b8b6c>
### * NOTE: All steps need to be run in this block, otherwise, we are operating back
### on the mac host
set -exo pipefail
#
### Basic user setup ################################################################
TEST_USER=tester
TEST_USER_HOME="/opt/$TEST_USER"
REPO_NAME=${GITHUB_WORKSPACE##*/}
WORKSPACE_PARENT="/Users/runner/work/${REPO_NAME}"
WORKSPACE="${WORKSPACE_PARENT}/${REPO_NAME}"
OS_VERSION="$(freebsd-version | awk -F- '{print $1}')"
PUB_INTF="$(netstat -4rn | grep default | awk '{ print $4}')"
ifconfig
#
mkdir -p "$TEST_USER_HOME"
pw adduser -n "$TEST_USER" -d "$TEST_USER_HOME" -c "Tester" -h -
chown -R "$TEST_USER":"$TEST_USER" "$TEST_USER_HOME"
chown -R "$TEST_USER":"$TEST_USER" "/$WORKSPACE_PARENT"/
whoami
#
### Output some information about the environment ##################################
# environment
echo "## environment"
env | sort
# tooling info
echo "## installed packages"
pkg info
#
### Create zpool ####################################################################
dd if=/dev/zero of=/zfs1 bs=1 count=1 seek=2G
zdev=$(mdconfig -a -t vnode -S 4096 -f /zfs1)
zpool create -f zroot "$zdev"
#
### Configure pf and pot ############################################################
echo "set skip on lo0" >/etc/pf.conf
echo pass >>/etc/pf.conf
service pf enable
service pf start
pw groupadd pot
bin/pot init
#
### Run CI tests ################################################
cd "$WORKSPACE"
cp -f etc/pot/pot.default.conf etc/pot/pot.conf
cd tests/CI
set +e
FAULT=0
./run.sh || FAULT=1
echo "Log output:"
cat pot-ci-*
if [ $FAULT -ne 0 ]; then exit 1; fi
#
### Finished ########################################################################
echo "Done"
================================================
FILE: .github/workflows/main.yml
================================================
# This is a basic workflow to help you get started with Actions
name: unit-test
# Controls when the action will run. Triggers the workflow on push or pull request
# events but only for the master branch
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
# This workflow contains a single job called "build"
build:
# The type of runner that the job will run on
runs-on: ubuntu-latest
# Steps represent a sequence of tasks that will be executed as part of the job
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: actions/checkout@v2
# Runs a single command using the runners shell
- name: Run a one-line script
run: cd tests && ./test-suite.sh
================================================
FILE: .github/workflows/shellcheck.yml
================================================
name: Shellcheck
on: [ pull_request ]
jobs:
shellcheck:
name: Shellcheck
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Run ShellCheck
uses: ludeeus/action-shellcheck@master
with:
scandir: share/pot
additional_files: bin/pot
================================================
FILE: .gitignore
================================================
/doc
*.swp
*~
/etc/pot/pot.conf
/etc/pot/flavours/*
!/etc/pot/flavours/dns.sh
!/etc/pot/flavours/dns
!/etc/pot/flavours/slim.sh
!/etc/pot/flavours/fbsd-update.sh
devenv.sh
/tests/CI/pot-ci*
================================================
FILE: .travis.yml
================================================
language: bash
script: cd tests && ./test-suite.sh
================================================
FILE: CHANGELOG.md
================================================
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
## Unreleased
### Added
- import/prepare: Support setting a default signature public key to verify pot signature (#296)
### Fixed
- prune: Only attempt to stop pot if it is running (#295)
## [0.16.0] 2023-12-30
### Added
- tinirc: Write tinirc's pid to /tmp/tinirc.pid (#277)
- set-attr/stop: Add attributes exec_stop and stop_timeout (#275)
- init/de-init: Add flag "-m" to be minimally intrusive, add flag -p to specify pf file (#284)
- init: Add flag -s to not alter syslogd settings, deprecate flag -f pf_file, as it is replaced by -p (#284)
- vnet: Add global configuration POT_ISOLATE_VNET_POTS to prevent direct traffic between VNET pots (#283)
### Fixed
- tinirc: Overwrite tinirc on start instead of appending to an existing file (#277)
- start: Fix setting of nullfs attribute
- set-status: Ignore status files that predate system boot (#278)
- set-status: Forward verbosity flags (#279)
- network: Find bridge interfaces by interface group, this allows custom bridge names (#282)
## [0.15.6] 2023-09-29
### Added
- start: Add custom pf rule configuration hook, POT_EXPORT_PORTS_PF_RULES_HOOK (#273)
- Remove basepath from mountpoint, make mount-in/out errors more visible (#259)
## [0.15.5] 2023-06-29
### Added
- set-attr: Add support for setting devfs_ruleset (#270)
- set-attr: Add support for setting mlock, sysvshm, sysvsem, sysvmsg, retire sysvipc attribute, which was always a noop (#263)
### Fixed
- pot-cmd: Output problems with pot root to stderr (#254)
- version: Don't require pot root to exist to run version command (#253)
- mount-in: Skip empty lines in fscomp.conf during mount process (#258)
## [0.15.4] 2022-12-15
### Added
- set-attr: add jail attributes "raw_sockets", "sysvipc" (#247, #248)
- import/export/prepare: support signing pots (#221)
### Changed
- flavours: scripts are made executable when loading
- destroy: remove status file when destroying
- vnet: use unique epaira interface names (#232)
- Add pot group to protect pot root (#240)
### Fixed
- Reverted the change of permissions of pot root mountpoint to fix a regression (#233)
- set-attr: fix no-etc-hosts attribute handling
- Remove leftover mount points on destroy (#236)
- set-attr/get-attr: fix help output (#245)
- Fix running flavour script on non-persistent pot (#238)
## [0.15.3] 2022-09-17
### Fixed
- stop: Destroy epair interface if stop is not called from start (#229)
## [0.15.2] 2022-09-17
### Fixed
- start: fix pot getting stuck in state "starting" on pot start failure (#227)
## [0.15.1] 2022-09-16
### Fixed
- set-status: fix a bug that deletes the status (#224)
## [0.15.0] 2022-09-11
### Added
- mount-out: new command to remove or unmount a previously mount-in folder or fs
- attribute no-tmpfs: an attribute, for single dataset only, to not use tmpfs for /tmp
- create/import: inherit ZFS encryption property from parent filesystem (#196)
- attribute no-etchosts: an attribute, to not inject additional /etc/hosts entries from `potnet`
- last-run-stats: new command to get statistics on the last run of a pot, currently contains "ExitCode", which is the exit code of pot.cmd (#200)
- start: return with code 125 in case pot.cmd of a non-persistent pot failed (#200)
- tinirc: wait for epair interface, exit early if it doesn't become available (#204)
- ifconfig: label and group interfaces created by pot (#206)
- clone: add dns option, to customize DNS configuration while cloning (#199)
- prepare: add -d option to change dns configuration during clone (#192)
- signal: send signals to processes running inside a pot (#216)
- exec: command to execute programs inside a running pot (#217)
### Changed
- Stop logging trivial commands like get-rss to syslog by default (#190)
- get-rss: test if the pot is running, instead of it only exists during input validation
- mount-in: mountpoint cannot contain spaces anymore (#187)
- start: allow pots to run for less than 5 seconds (#200)
- start: always stop and cleanup non-persistent pots once pot.cmd finished, prevents stray background tasks from keeping them alive (#200)
- prune: add flag "-g" to delay pruning of pots that just stopped, so users have a chance to inspect last-run-stats (#200)
- help: rework usage screens (#209)
- prepare: enable attribute no-tmpfs and no-etc-hosts (#192)
- tests: improved monitoring of tests, requires sysutils/flock on FreeBSD (#220)
- Change permissions of pot root mount point to be only accessible by root user (#218)
### Fixed
- start: correct invocation of prestart and poststart hooks (#200)
- tinirc: configure address selection policy (#205)
- fdescfs/procfs: fixed the correcte behavior of those attribute, such as mount them at start
- mount-out: fix it
- clone: fix cleanup after failed clone (#214)
- start/stop: heavy rework to fix concurrency (#202)
## [0.14.0] 2021-10-31
### Added
- copy-in: -c option to create missing dirs on copy-in (#172)
- create: New command copy-in-flv, which is the same as copy-in, but always relative to flavourdir (#173)
- init: -f option to specify pf file to patch on init (#181)
### Changed
- start: do not write jid files to POT_TMP (#178)
- start/stop: remove pot_stopped files from TMP_DIR after stopping non-persistent jails (#179)
### Fixed
- prepare: fix -N option to allow network-type "host" as used by nomad-pot-driver (#177)
- copy-in: fix tmp source directory creation
## [0.13.0] 2021-09-21
### Added
- import-export: add support for layered images (#151)
- POT_TMP: add a parameter to select the folder used to create temporary files
- flavour: -f option support a full pathname (#161)
- copy-out: new command to copy file or folder out from a pot (#162)
### Changed
- start: simplify startup, use jexec to run pot.cmd (#150)
- flavour: the current directory is added to the flavour search path (#161)
### Fixed
- start/stop: prevent stopping non-persistent jails twice (#152)
- stop: garbage collect POSIX shared memory (#150)
- start: fix ncat failing to start due to argv handling (#167)
## [0.12.0] 2021-05-22
### Added
- pot.conf: add parameter to control max hostname length inside the pot (#118)
- CI: add shellcheck as hard requirements in the PR flow
- export-ports: add UDP support, as -e udp:53:53 (#115)
- create: dns custom allows to statically provide a resolv.conf
- POT_EXTIF_ADDR: new parameter to force which IP of EXTIF should be used for NAT and RDR
- clone: add support for applying flavors to cloned pots
- clone: add -k flag to keep the cloned pot for debug when the process failed
- info: -s to list available snapshots of a pot
- clone: -s flag to explicitly choose the snapshot to clone
- architecture: remove limitation of amd64 as the only architecture supported (#143 by jmg@)
- start/stop/term/run: add support to -p potname on those commands, the only one not supporting it
### Changed
- hostname: max default length for hostname set to 64 (#118)
- create: adopt the new hostname length parameter (#118)
- clone: adopt the new hostname length parameter (#118)
- ext-if: do not include interface aliases in the bridges network if EXTIF has them (#120)
- start: add support for custom dns resolver
- init: create backup of rc.conf and pf.conf before to apply pot related changes
- info: -B instead of -b for private bridge information
- copy-in: copy is executed in the jail environment, to avoid soft-link related issues in the destination path
- copy-in: with running pots, a -F flag is needed to force the copy, an operation that is discouraged for security reasons
- fetch base.txz: the base FreeBSD tarball used to be temporarily stored in /tmp. While a POT_CACHE folder is available, use that instead.
### Removed
- create-dns: remove this already deprecated command, leaving the user to create a dns for the public bridge
### Fixed
- zsh: fix autocompletion for set-hook (#139 by urosgruber)
## [0.11.6] 2020-12-14
### Fixed
- stop: remove resolv.conf only if dns is not off (#117)
## [0.11.5] 2020-11-21
### Added
- create: dns off allows to skip the resolv.conf configuration
### Fixed
- start: (FreeBSD 12.2) pf fails to load rdr rule in some cases
## [0.11.4] 2020-09-12
### Added
- set-attr: add many jails attributes: enforce_stats mount fdescfs libprocfs nullfs procfs tmpfs zfs children
### Fixed
- localhost-tunnel: fix multiple port support (#108)
## [0.11.3] 2020-08-03
### Changed
- start: remove temporary files (#91 #92)
### Fixes
- clone: fix a typo refactoring the grep that remove network parameters (#90)
- mount-in: fix mountpoint validation when pot is stopped and -v is passed (#93)
- clone: hooks have been ignored by clone (#94)
- info: fix withespace quoting with -E flag (#95)
- prepare: fix -i command to allow multiple IP addresses (#97)
- ifconfig: force IFCONFIG_FORMAT to avoid conflicting user setting (#99)
## [0.11.2] 2020-05-01
### Added
- prepare: the -S option is now used to specify the network stack
### Changed
- prepare: the -S flag to start the imported pot changed in -s
### Fixed
- fbsd-update: don't assume there is a tty (#86)
- clone: duplicate the entry pot.stack (#88)
## [0.11.1] 2020-04-19
### Fixed
- set-attr: attribute early-start-at-boot is now correctly recognized
## [0.11.0] 2020-04-19
### Added
- create-base: automatically call freebsd-update when a base is created (#83)
- attribute early-start-at-boot: for pot needed to start early at boot (REQUIRE: NETWORKING syslogd pf)
- create: add a -k flag to keep the pot, even if it's creation process failed
- network stack: add network stack as framework concept (ipv4, ipv6 or dual)
- CI: import the run.sh script, with regression system tests
- alias: the new notation -i can be repeated to assign multiple IPs to different NICs
- hooks: added variables to provide the full new alias network configuration
### Changed
- osrelease: detect it from freebsd-version, deprecating the osrelease field in pot.conf (#83)
- start-at-boot: the pot rc.d service will be executed late, with jail
- create: if create fails, the partially created pot is automatically destroyed
- create: -P will use send/receive from a snapshot, to cut the dependency with the snapshot
- create-multi: usr.local and custom dataset are send/received instead of cloned
- inherit: it inherits the stack configured in pot.conf
- alias: extend -i option to accept netif|ipaddr
- alias: -i option can be repeated more than once to add more ip addresses to the same instance
- syslogd: initial removal of syslogd forwarding
### Removed
- alias: remove option -I, in favour of a more flexible and powerful -i
- export: remove option -s, to select a specific snapshot (already deprecated)
- snapshot: remove option -n, to specify a snapshot name (already deprecated)
- snapshot: remove flag -a, to snapshot external ZFS datasets (already deprecated)
- revert: remove flag -a, to restore external ZFS datasets (already deprecated)
### Fixed
- mount-in: compute the realpath of the mount-point
- create: use pipefail only where implemented
- ipv6: rtsold doesn't start in a jail on 11.3
## [0.10.4] 2020-02-23
### Added
- alias: add ability to use a different network interface for alias network type (#80)
- env: add pot info -E output to environment or tinirc
- log: add the ability to log activites in syslog
### Fixed
- prepare: fix multiple export port support
- rc script: extend PATH to make potnet accessible
- etc/hosts: add full hostname to localhost
## [0.10.3] 2020-01-07
### Changed
- export-ports: relax the check bout the pot's network type
- list: print a message, if there are no pot yet
## [0.10.2] 2019-12-17
### Added
- fbsd-update flavour: add a flavour to run freebsd update
### Changed
- slim flavour: remove a bounch of other directories
### Fixed
- flavor: set-cmd can cause issue if it has quotes or double quotes in the command string
- tinirc: lo1 initialization needed only for public or private bridge
- start: background tasks now check if the pot is running
- init: fix bridge folder creation
- prepare: fix prepare when no command is provided (-c is optional)
## [0.10.1] 2019-12-04
### Added
- set-hooks: add support for pre/post start/stop hooks. Script are executed in the host environment (#61)
### Changed
- home-usr/home: those link are not always available. Change create and crate-base to have them always (reported by Philip Jocks)
### Fixed
- create: permission of /tmp in single type are wrong (#72)
- create: if FreeBSD base fetch is interrupted, a broken file is left and the checksum will always fail (#73)
- import: if the image fetch is interrupted, a broken file is left and the checksum will always fail
- import: fix hostname rename
- localhost-tunnel: fix kill of ncat tunnel, when the pot has a long name
## [0.10.0] 2019-11-01
### Added
- info: support for bridge
- set-hosts: new command to add custom etc/hosts entries to a pot
- set-env: new command to add environment variable to a pot
- network-type private-bridge: add a new network layout, to provide private bridges for a group of pots
- create-private-bridge: new subcommand to define and create a private-bridge
- create: add option -B, to provide the bridge name if network-type is private-bridge
- clone: add option -B, to provide the bridge name if network-type is private-bridge
- prepare: add option -B, to provide the bridge name if network-type is private-bridge
- destroy: add option -B, to provide a way to destroy a bridge
- Image Guide: added a guide about how to create an Image of a pot
- POT_EXTRA_EXTIF: add addition network interfaces support
### Changed
- start: overwrite /etc/hosts of a pot, adding all pots on the same bridge and custom entries added via set-hosts
- flavorable commands: extend support to set-cmd and set-env
- pot-rdr anchor: the name of the anchor is now a truncated pot name (the last 54 characters)
- export: it's executed only if one snapshot is available. -F force execution, -A fix the number of snapshots, via purge-snapshots or taking a shapshot automagically
- start: using exec.start instead of command (it seems more predictable)
### Deprecated
- snapshot: -n option to provide custom name to snapshots
- support to full pot snapshot (external zfs dataset) in snapshot and start, as well as the _pot_zfs_snap_full function
- support to full pot revert (external zfs dataset) in revert/rollback (option -a)
- create-dns: undocumented and too hard to maintain
- export: -s option, to specify a snapshot. It's misleading, because zfs send -R will send all the previous snapshots anyway
### Fixed
- flavorable commands: they cannot exit, but return. create can stop flavour execution otherwise
- show: fix single type support and directory in fscomp.conf
- start: if the command has arguments with equals, it would have been truncated
## [0.9.2] 2019-08-25
### Added
- prune: invoke a stop, before the destroy, even if the pot is not runing
- lockf: introducing lockf to run create, import or clone one at a time
### Fixed
- stop: make the pkill on ncat more robust
- stop: add a workaround for a race condition in the epair driver
## [0.9.1] 2019-08-20
### Added
- localhost-tunnel attribute: new attribute to create a tunnet to redirect traffic from localhost (consul feature)
### Changed
- prepare: allow network type "host" as alias for "inherit" (nomad-friendly feature)
- prepare: set localhost-tunnel automatically (consul-friendly feature)
### Fixed
- get-rss: fix return code when the pot is not valid
- set-cmd: fix potential double quotes surrouding the command
- get-rss: TotalTicks is now expressed in Mhz (pcpu * max cpu Frequency)
- get-rss: add swap usage statistic
- start: fix tinirc permission if no-rc-script is used with network type different than public-bridge
- destroy: use -f to remove the 'Device busy' issue
## [0.9.0] 2019-08-13
### Added
- Installation Guide: a more detailed guide, that better explains the installation of pot
- fdescfs attribute: new attribute to mount fdescfs inside the pot
- init: add a network configuration validation step
### Changed
- POT_CACHE: the cache used by import is now a dataset, child of POT_ZFS_ROOT
- set-rss: CPU limits is set as maximum amount of CPU. At start, pot decide where to allocate using potcpu
- prunable: if a pot is prunable, it has to be started at least once to be pruned (flavour counts)
## [0.8.0] 2019-07-30
### Added
- update-config: implemented -a flag to update all pot configurations in one run
- get-rss: show the current resources usage (output available in json)
- procfs attribute: new attribute to mount a procfs inside the pot
- prunable attribute: new attribute prunable, to automatically delete not running pots (prune)
- prune: new command to automatically destro yinactive prunable pots
### Changed
- create: rework how to configure the network type of a pot
- Quickstart Guide: rework the guide using mount-in and copy-in, listing all possibilities
- README: remove the introduction and pointing to the Quickstart guide instead
- import: removed -a option, not really needed during import
- prepare: optimized, importing once and using clone instead of import+rename every time
- clone: add -N option, to change network type while cloning
- prepare: add -N option, to change network type while preparing
### Removed
- promote: after a long deprecation time, promote has been deleted
- add-fscomp: removed, mount-in is its more generic replacement
- add-file: removed, copy-in is its more generic replacement
- execute: remove this alias of prepare
### Fixed
- start: if the start command doesn't go in background, rss and persist weren't managed
## [0.7.0] 2019-07-04
### Added
- update-config: new command that will update a pot configuration
- execute: an orchestration oriented command that imports and automatically set several settings on a pot
- prepare: new command, taking the place of execute
- copy-in: new command, to copy files or directory inside a pot (generalized replacement of add-file)
- mount-in: new command, to mount a directory, a zfs dataset or a fscomp inside a pot (replacement for add-fscomp)
### Changed
- export-ports: removed -S for static port export
- export-ports: add the ability to associate any host port to a pot port to be exported using pot_port:host_port format
- execute: an alias for prepare
### Deprecated
- add-file: deprecated, replaced by the more general new copy-in command
- add-fscomp: deprecated, replaces by the more general new mount-in command
## [0.6.1] 2019-06-25
### Fixed
- init: make pf.conf more robust
- vnet-start: make pf start more robust, in case pf as service is not up
## [0.6.0] 2019-06-23
### Added
- add-fscomp: add option -d, to allow to mount generic directories into a pot (-d and -f are mutual)
- show: add -q flag, to only show pot names
- set-attribute: to set pot attributes (options/flags/configurations)
- get-attribute: to get pot attributes (options/flags/configurations)
- FreeBSD version usable to create a pot are all the ones listed in the FreeBSD MANIFEST
- attributes: add persistent attribute to jail
- attributes: add no-rc-script attribute to start a pot without a rc script
- add-file: new command to copy a single file inside a pot
### Changed
- inherit network: added ipv6 support (automatic)
- static IP network: added ipv6 support
- pf: adopt anchor with relevant changes in nat rules management
### Deprecated
- pot_list: in rc.conf pot_list is not supported anymore. Please use the start-at-boot attribute
### Fixed
- syntax error in zsh autocompletion
- ls fscomp: using zfs instead of ls (if a fscomp is re-mounted, the mountpoint is not in /opt/pot/fscomp anymore)
- static-ip: Fix invocation to potnet to validate ip addresses
## [0.5.11] 2019-03-04
### Added
- export: new command. export generates a compressed file with the entire pot in it. It works only for single type pot
- export: -D option to change export directory and -l option to change compression level
- POT_CACHE: a place to cache pot images. It's a variable of pot.conf
- import: new command. import create a new pot based on an image generated via export
- import-export: add skein has verification support
### Changed
- rc.d: changed order, to start pot before ntpdate
- destroy: extend the usage of -F to be able to destroy corrupted pots
### Fixed
- destroy: fix return code
- rename: fix single pot support
- get_conf_var: using a better RE to avoid to detect variables value in pot names (Thanks to Johan Hendriks to report)
## [0.5.10] 2019-01-15
### Added
- destroy: option -f can be used to delete/destroy a fscomp (no recursive support yet)
- vnet-start: add support to VPN and custom pf configuration
### Changed
- destroy: option -f (force) is now -F
### Fixed
- is_pot: improve support to single pots, that don't have fscomp.conf file
- create-base: fix regression introduced on 0.5.9 (RC support and create -F removal)
## [0.5.9] 2018-12-16
### Added
- Add support to RC FreeBSD version
- config: add pot_prefix and fscomp_prefix as possible values
- snapshot: add option -n to give a name to the snapshot; valid for fscomp only
- Add support to FreeBSD 12.0
### Changed
- create: removed -F option and silent default flavor invocation. Default flavor has to be explicitely selected via -f
- create-base: removed support for undocumented default-base flavor
## [0.5.8] 2018-11-29
### Added
- QuickStart.md : a markdown quick guide, for new users
- create : -i auto (based on potnet) to get automatically a valid IP address
- clone : -i auto (based on potnet) to get automatically a valid IP address
- clone : add support to single type pot
- export-port : new command that allow pot ports to be exposed outside (vnet case)
- slim flavor, designed to be used with single dataset pot types
- purge-snapshot : new command that will remove all snapshots, except the last one
- export-port : static option, to add statically exported ports
### Changed
- init : it takes care of syslogd configuration in the host system
- create : type=single will install plain FreeBSD and run the default flavour
- create : multiple flavour support, executed in sequentially; option -f can be repeated
- add-fscomp : exploit the new internal refactorized mount and umount function to avoid to start the pot
- add-fscomp : if the pot is running, mount the new fscomp right away
### Fixed
- clone : fix a misleading/false positive error message
- clone : fix syslogd configuration in the cloned pot
- destroy : fix if pot is a single dataset one
- start : fix hostname warning
- start (#046) : run the jail in a clean enviroment
- term (#046) : spawn the shell in a jail using the jailed user environment
- add-fscomp (#045) : check the mount point and create it, if missing
- list (#052) : fixing xargs invocation
### Deprecated
- promote : mark promot as deprecated, so we can remove it in the next major release
## [0.5.7] 2018-06-28
### Added
- create-base : add support to FreeBSD 11.2
### Fixed
- version (#038) : fix the version number showed
## [0.5.6] 2018-05-18
### Added
- create-base : add option -b, to provide a specific name to a base and support multiple bases with the same FreeBSD version
- create: add support to single dataset pots.
- set-cmd: add the command to manage the command line that starts the container
- top: add a new command, to spawn a top only on a pot
## [0.5.5] 2018-04-18
### Added
- ps : add ps subcommand, to show information about which pot is running
- config : add config subcommand, to easily access configuration values
- zsh autocompletion (#013): pot autocompletion support for zsh
- syslogd log unification (#032): when possible, syslogd autoconfigured to log in the host instead of in the pot
### Changed
- list : keep it more simple, leaving more information under -v
- show : add -r (all running pots) option and made it the new default
- show : -a greatly improved show all relevant information per pot
### Removed
- fs.conf is not supported anymore
## [0.5.0] 2018-03-16
### Added
- add-fscomp : add the ability to remount a fscomp (-w), instead of mount it via nullfs
- add-fscomp : add the ability to mount a fscomp in read-only (-r)
- info : new command, to get information about a specific pot
- rc.d script (#022)
- create (#020) : add option -s, to configure static ip address (alias to external network interface)
- create-base (#030) : add sha verification using freebsd-release-manifests
- version : add a subcommand the print the current version of the utility
- fscomp.conf : new fs component description file
- clone : -f option to automatically get a snapshot of a dataset, if needed
- promote (#008) : add promote command
### Changed
- create: the new wiki page shows the slightly different behavior of all use cases
- create: fscomp.conf is generated instead of fs.conf, using dataset instead of mountpoint as first column
- private datasets are now mounted changing the mountpoint of the dataset, instead of relying on nullfs
For that reasons, an option called "zfs-remount" is added to the fs.conf file
### Deprecated
- fs.conf: fs.conf is deprecated. Support will be removed in the next release.
### Removed
- create: -S option, not needed anymore
## [0.4.0] 2018-02-13
### Added
- rollback : added rollback as alias of revert
- help : add support for aliases
- add-fscomp (#027): add support for external ZFS dataset via the option -e
- de-init (0#23): new command to completely remove (de-install) pot from your system
### Fixed
- stop (#024): check the pot existance
- stop : fixed error messages referring to "jail"
- list : fix help, option -s never implemented
- destroy (0#25): fix pot name validation and add dependency detection
## [0.3.1] 2018-01-26
### Added
- pot.conf.sample : a documentated pot.conf example
## [0.3.0] 2018-01-26
### Added
- Every command that need root privileges perform a check of the user id
- create (#010): add a validation of command types executable in a pot flavour
- Checks about VIMAGE and rctl usability (#018)
### Changed
- set-rss : rename command (it was add-rss)
- vnet-start (#019): automatic activation of ip forwarding
### Fixed
- create-base (#016): do not re-create the base pot
- rename (#017): apply the rename also in dependents pots (level 2 or runtime dependency)
- create (#021): -b argument validation
## [0.2.0] 2018-01-23
### Added
- create-dns : new command, to create the dns pot
- create : add the option -d to choose the type of dns (inherit or pot)
- start : add the support to dns types
### Fixed
- rename : remove a misleading error message
- start : proper stop, if one mount fails
- vnet-start (#009): pf module loaded and firewall enabled
## [0.1.0] 2017-12-14
### Added
- Add resource constraints, via add-rss command
- Add clone-fscomp command, to clone a fscomp
- Add clone command, to clone a pot
- Add rename command, to completely rename a pot
- Add dependency support, and related command add-dep
- Add support to destroy bases and their related level 0 pot
- Add support to recursive destroy
- Add support to default flavour with create-base
- Add -F option to create, to disable the default flavour
- More tests
### Changed
- Move packages db to the usr.local dataset - it's a breaking change
## [0.0.2] 2017-12-03
### Fixed
- Fixed start, a typo prevents the correct behavior
## [0.0.1] 2017-12-03
### Added
- Add a revert command, to rollback a pot snapshot
- Add snaposhot information in list command
- Add a test framework
- Add travis-ci support
### Changed
- snapshot options has changed to be more consistent and to support fscomp
- revert options has changed to be more consistent and to support fscomp
### Fixed
- If a start fails, it tries to clean up (umount)
## [0.0.1-rc.1] 2017-11-28
### Added
- Add a vnet-start command, to properly init the vnet network configuration (bridge+pf)
- Add an option to show, to show all pot resource usage
- Add some command alias: ls is an alias of list
- Auto-start of vnet, when needed
- Add level 2 pot support, adding special option -P and -S in create command
- Add a run command, to start and enter in a pot
- Add a -f option to destroy and term, to fix/force the operation
- Add -F for flavor and -a for all in list command
### Changed
- Changed pot configuration. No jail.conf anymore, but pot.conf
- Pots with an ip are now based on epair/vnet/VIMAGE technology
- Command show now shows resource usage of all pots by default
- Add more information in show and list command
### Deprecated
- jail.conf files are currently ignored, please destroy and recreate pots
### Removed
- scripts directory and j\* commands in bin. None of them could really works
## [0.0.1-beta] 2017-11-07
### Added
- Add option -b to list, to list available bases
- Add option -f to list, to list available fs components
- Add a destroy command, to destroy a pot
- Add a term command, to start a pot
- First implementation of show, that shows memory used by running pots
- Add support to flavour- pot subcommand and shell script
### Changed
- Remove jail references and use pot instead (not in zfs)
- jstart command is now start
- jstop command is now stop
- create-jail command is not create
- create-base creates the related level 0 pot automatically
- start doesn't invoke exit if succeeds
### Fixed
- Fix add-fscomp that can introduce valid, but imprecise mount-point
- Fix create-base that created a wrong usr.local.etc link
## [0.0.1-alpha] 2017-10-20
### Added
- Add the central utility called 'pot'
- Add a central configuration file
- Add a init command, to initialize the zfs layout
- Add a create-base command, to create a new base
- Add a create-fscomp command, to create a new base
- Add a create-jail command, to create a new base
- Add a jstart command, to start a pot
- Add a jstop command, to stop a pot
- Add an option to jstart, to take a snapshot of the pot before the start
- Add a help command, to show subcommand helps
- Add a list command, to list of pots
- Add a add-fscomp command, to add fscomponents to pots
- Add a snapshot command, to take a snapshot of a pot
### Changed
- After long time spent on thinking, the project has a new nice name, pot.
================================================
FILE: Jenkinsfile
================================================
pipeline {
agent any
environment {
TERM = 'rxvt'
}
stages {
stage('Test') {
steps {
sh 'echo "Hello World"'
sh '''
cd tests
./test-suite.sh
'''
}
}
}
}
================================================
FILE: LICENSE
================================================
BSD 3-Clause License
Copyright (c) 2017, Luca Pizzamiglio
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
================================================
FILE: README.md
================================================
# THIS REPOSITORY IS NO LONGER ACTIVELY MAINTAINED, IT HAS MOVED TO https://codeberg.org/bsdpot/pot
# pot
[](https://github.com/pizzamig/pot/actions) [](https://opensource.org/licenses/BSD-3-Clause)
Another container framework based on jails, to run FreeBSD containers on FreeBSD.
Every running instance is called `pot`, like the one that I use to cook all the different type of pasta.
It's heavily based on FreeBSD, in particular on jails, ZFS, pf and rctl.
The project's initial goal was to prove that FreeBSD has all the technologies to have a container-alike environment.
The project then evolved into something more robust and feature-rich.
The project was presented for the first time at FOSDEM 2018: ([talk page](https://archive.fosdem.org/2018/schedule/event/pot_container_framework/))
If you are more interested in jail orchestration, a nomad driver is provided to interact with `pot` and this work has been presented at FOSDEM 2020 ([talk page](https://archive.fosdem.org/2020/schedule/event/orchestrating_jails/))
### Documentation
The project's documentation is available at [https://pot.pizzamig.dev](https://pot.pizzamig.dev)
More in details:
* A Getting started guide is available [here](https://pot.pizzamig.dev/Getting)
* An installation guide, with detailed description is available [here](https://pot.pizzamig.dev/Installation)
### Nomad pot driver integration
A driver to allow [nomad](https://www.nomadproject.io) to interact with `pot` has been developed and available [here](https://github.com/trivago/nomad-pot-driver)
### Ansible Collection
There is pot collection for Ansible provided by github user @zilti available at https://galaxy.ansible.com/zilti/pot.
### Online help
`pot` provide an online help:
```
# pot help
Usage: pot command [options]
Commands:
help -- Show help
version -- Show the pot version
config -- Show pot framework configuration
ls/list -- List of the installed pots
show -- Show pot information
info -- Print minimal information on a pot
top -- Run the unix top in the pot
ps -- Show running pots
init -- Initialize the ZFS layout
de-init -- Deinstall pot from your system
vnet-start -- Start the vnet configuration
create-base -- Create a new base image
create-fscomp -- Create a new fs component
create-private-bridge -- Create a new private bridge
create -- Create a new pot (jail)
clone -- Clone a pot creating a new one
clone-fscomp - Clone a fscomp
rename -- Rename a pot
destroy -- Destroy a pot
prune -- Destroy not running prunable pots
copy-in -- Copy a file or a directory into a pot
mount-in -- Mount a directory, a zfs dataset or a fscomp into a pot
add-dep -- Add a dependency
set-rss -- Set a resource constraint
get-rss -- Get the current resource usage
set-cmd -- Set the command to start the pot
set-env -- Set environment variabls inside a pot
set-hosts -- Set etc/hosts entries inside a pot
set-hook -- Set hook scripts for a pot
set-attr -- Set a pot's attribute
get-attr -- Get a pot's attribute
export-ports -- Let export tcp ports
start -- Start a jail (pot)
stop -- Stop a jail (pot)
term -- Start a terminal in a pot
run -- Start and open a terminal in a pot
snap/snapshot -- Take a snapshot of a pot
rollback/revert -- Restore the last snapshot
purge-snapshots -- Remove old/all snapshots
export -- Export a pot to a file
import -- Import a pot from a file or a URL
prepare -- Import and prepare a pot - designed for jail orchestrator
update-config -- Update the configuration of a pot
```
Every command has its own online help as well. For instance:
```
pot create [-hv] -p potname [-N network-type] [-i ipaddr] [-l lvl] [-f flavour]
[-b base | -P basepot ] [-d dns] [-t type]
-h print this help
-v verbose
-k keep the pot, if create fails
-p potname : the pot name (mandatory)
-l lvl : pot level (only for type multi)
-b base : the base pot
-P pot : the pot to be used as reference
-d dns : one between inherit(default), pot, off or custom:filename
-f flavour : flavour to be used
-t type: single or multi (default multi)
single: the pot is based on a unique ZFS dataset
multi: the pot is composed by a classical collection of 3 ZFS dataset
-N network-type: one of those
inherit: inherit the host network stack (default)
alias: use a static ip as alias configured directly to the host NIC
public-bridge: use the internal commonly public bridge
private-bridge: use an internal private bridge (with option -B)
-i ipaddr : an ip address or the keyword auto (if compatible with the network-type)
auto: usable with public-bridge and private-bridge (default)
ipaddr: mandatory with alias, usable with public-bridge and private-bridge
-B bridge-name : the name of the bridge to be used (private-bridge only)
-S network-stack : the network stack (ipv4, ipv6 or dual)
```
================================================
FILE: bin/pot
================================================
#!/bin/sh
# Copyright (c) 2017, Luca Pizzamiglio <pizzamig@FreeBSD.org>
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# * Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# Force ifconfig into expected format
export IFCONFIG_FORMAT=addr:default
# Environment initialization and initial checks
# shellcheck disable=SC2034
_POT_VERSION=0.16.0
_POT_PATHNAME="$(realpath "$0")"
_POT_PREFIX="$(dirname "${_POT_PATHNAME}")"
_POT_INCLUDE="$( realpath "${_POT_PREFIX}/../share/pot")"
_POT_ETC="$( realpath "${_POT_PREFIX}/../etc/pot")"
if [ -d "${_POT_ETC}/flavours" ]; then
_POT_FLAVOUR_DIR="$( realpath "${_POT_ETC}/flavours")"
else
# shellcheck disable=SC2034
_POT_FLAVOUR_DIR=
fi
if [ ! -d "${_POT_INCLUDE}" ]; then
echo "Fatal error! Not able to find the subroutines directory as ${_POT_INCLUDE}!"
exit 1
fi
# loading subroutines
if [ ! -r "${_POT_INCLUDE}/common.sh" ]; then
echo "Fatal error! Not able to find common subroutines in ${_POT_INCLUDE}!"
exit 1
fi
# shellcheck disable=SC1090
. "${_POT_INCLUDE}/common.sh"
if [ ! -r "${_POT_INCLUDE}/common-flv.sh" ]; then
echo "Fatal error! Not able to find flavor subroutines in ${_POT_INCLUDE}!"
exit 1
fi
# shellcheck disable=SC1090
. "${_POT_INCLUDE}/common-flv.sh"
if [ ! -r "${_POT_INCLUDE}/network.sh" ]; then
echo "Fatal error! Not able to find network subroutines in ${_POT_INCLUDE}!"
exit 1
fi
# shellcheck disable=SC1090
. "${_POT_INCLUDE}/network.sh"
# loading configuration
if [ -r "$_POT_ETC/pot.default.conf" ]; then
# shellcheck disable=SC1090
. "$_POT_ETC/pot.default.conf"
else
_error "Fatal error! Not able to find default configuration file on $_POT_ETC"
exit 1
fi
if [ -r "$_POT_ETC/pot.conf" ]; then
# shellcheck disable=SC1090
. "$_POT_ETC/pot.conf"
fi
usage() {
cat <<-"EOF"
Usage: pot command [options]
Commands:
help -- Show help
version -- Show version of the pot command
config -- Show pot framework configuration
ls/list -- List of the installed pots
show -- Show information on pots
info -- Print minimal information on a pot
top -- Run top(1) inside the pot
ps -- Show running pots
init -- Initialize the ZFS layout
de-init -- Remove pot from your system
vnet-start -- Start vnet configuration
create-base -- Create a new base image
create-fscomp -- Create a new fs component
create-private-bridge -- Create a new private bridge
create -- Create a new pot (jail)
clone -- Clone a pot, creating a new one
clone-fscomp -- Clone an fscomp
rename -- Rename a pot
destroy -- Destroy a pot
prune -- Destroy non-running, prunable pots
copy-in -- Copy a file or a directory into a pot
copy-out -- Copy a file or a directory out of a pot
mount-in -- Mount directory, ZFS dataset, or fscomp into a pot
mount-out -- Unmount directory, ZFS dataset, or fscomp from a pot
add-dep -- Add a dependency
set-rss -- Set a resource constraint
get-rss -- Get the current resource usage
set-cmd -- Set the command to start the pot
set-env -- Set environment variables inside a pot
set-hosts -- Set /etc/hosts entries inside a pot
set-hook -- Set hook scripts for a pot
set-attribute/set-attr -- Set an attribute on a pot
get-attribute/set-attr -- Get an attribute from a pot
export-ports -- Allows exposing tcp and udp ports
start -- Start a pot (jail)
stop -- Stop a pot (jail)
term -- Open terminal inside of a pot
run -- Same as term, but start pot if it is not running
snap/snapshot -- Take a snapshot of a pot
rollback/revert -- Restore the latest snapshot
purge-snapshots -- Remove old/all snapshots
export -- Export a pot to a file
import -- Import a pot from a file or a URL
prepare -- Import and prepare a pot, used by orchestrators
update-config -- Update the configuration of a pot
last-run-stats -- Get statistics about a pot's last run
signal -- Send signal to pot
exec -- Execute a progam inside of a pot
EOF
}
# shellcheck disable=SC2034
# variable initialization
_POT_VERBOSITY=1
# parsing command line subcommand
if [ $# -lt 1 ]; then
usage
exit 1
fi
CMD="$1"
shift
case "${CMD}" in
ls)
CMD=list
;;
rollback)
CMD=revert
;;
snap)
CMD=snapshot
;;
set-attr)
CMD=set-attribute
;;
get-attr)
CMD=get-attribute
;;
esac
case "${CMD}" in
help)
if [ -n "$1" ]; then
pot-cmd "${CMD}" "$1"
exit 0
else
usage
exit 0
fi
;;
show|version|config|\
list|info|ps|top|\
init|de-init|vnet-start|\
create-base|create-fscomp|create|\
create-private-bridge|\
copy-in|copy-out|mount-in|mount-out|prune|set-hook|\
destroy|add-dep|set-rss|get-rss|set-cmd|set-env|set-hosts|\
export|import|prepare|\
export-ports|set-attribute|get-attribute|\
start|stop|term|\
rename|clone|clone-fscomp|promote|\
snapshot|revert|purge-snapshots|update-config|\
last-run-stats|signal|exec|set-status)
pot-cmd "${CMD}" "$@"
exit $?
;;
run)
pot-cmd term -f "$@"
exit $?
;;
*)
usage
exit 1
;;
esac
================================================
FILE: etc/pot/flavours/dns
================================================
set-attribute -A start-at-boot -V YES
================================================
FILE: etc/pot/flavours/dns.sh
================================================
#!/bin/sh
pkg install -y dnsmasq
pkg install -y consul
pkg clean -ayq
if [ ! -d /usr/local/etc/consul.d ]; then
mkdir -p /usr/local/etc/consul.d
fi
_epair="$(ifconfig | egrep 'epair.*b' | cut -f 1 -d':')"
_ip="$( ifconfig $_epair inet | awk '/inet/ { print $2; }' )"
_ip1="$( echo $_ip | cut -f 1 -d'.' )"
_ip2="$( echo $_ip | cut -f 2 -d'.' )"
_domain="$( hostname | cut -f 2 -d'.' )"
echo "server=/${_domain}/127.0.0.1#8600" >> /usr/local/etc/dnsmasq.conf
echo "server=/0.${_ip2}.${_ip1}.in-addr.arpa/127.0.0.1#8600" >> /usr/local/etc/dnsmasq.conf
echo "listen-address=${_ip}" >> /usr/local/etc/dnsmasq.conf
sysrc dnsmasq_enable="YES"
sysrc consul_enable="YES"
sysrc consul_args="-server -dev -domain=${_domain} -bind=${_ip}"
================================================
FILE: etc/pot/flavours/fbsd-update.sh
================================================
#!/bin/sh
export PAGER=/bin/cat
freebsd-update --not-running-from-cron fetch install
================================================
FILE: etc/pot/flavours/slim.sh
================================================
#!/bin/sh
dirs="/usr/share/bsdconfig /usr/share/doc /usr/share/dtrace /usr/share/examples /usr/share/man /usr/share/openssl /usr/share/sendmail /usr/share/pc-sysinstall /usr/libexec/bsdinstall /usr/libexec/bsdconfig /rescue /usr/tests /usr/lib32 /usr/lib/clang /usr/include /var/db/freebsd-update /var/db/etcupdate /boot"
usr_bin="c++ c++filt c89 c99 cc CC cpp clang clang-cpp clang-tblgen clang++ gdb gdbtui gdbserver ld ld.bfd ld.lld lldb llvm-objdump llvm-tblgen nm objcopy objdump strings strip"
usr_bin_glob="svnlite yp"
usr_sbin="dtrace"
usr_sbin_glob="bhyve boot yp"
rm -f /usr/lib/*.a
## Remove pkg stuff
rm -rf /var/db/pkg/*
rm -rf /usr/sbin/pkg
rm -rf /usr/local/sbin/pkg
for d in $dirs ; do
rm -rf ${d}
done
(
cd /usr/bin
for f in $usr_bin ; do
rm -f $f
done
for g in $usr_bin_glob ; do
rm -rf ${g}*
done
)
(
cd /usr/sbin
for g in $usr_sbin_glob ; do
rm -rf ${g}*
done
rm -f $usr_sbin
)
================================================
FILE: etc/pot/pot.conf.sample
================================================
# pot configuration file
# All datasets related to pot use the some zfs dataset as parent
# With this variable, you can choose which dataset has to be used
# POT_ZFS_ROOT=zroot/pot
# It is also important to know where the root dataset is mounted
# POT_FS_ROOT=/opt/pot
# This is the cache used to import/export pots
# POT_CACHE=/var/cache/pot
# This is where pot is going to store temporary files
# POT_TMP=/tmp
# This is the group owning POT_FS_ROOT
# POT_GROUP=pot
# This is the suffix added to temporary files created using mktemp,
# X is a placeholder for a random character, see mktemp(1)
# POT_MKTEMP_SUFFIX=.XXXXXXXX
# Define the max length of the hostname inside the pot
# POT_HOSTNAME_MAX_LENGTH=64
# Internal Virtual Network configuration
# IPv4 Internal Virtual network
# POT_NETWORK=10.192.0.0/10
# Internal Virtual Network netmask
# POT_NETMASK=255.192.0.0
# The default gateway of the Internal Virtual Network
# POT_GATEWAY=10.192.0.1
# The name of the network physical interface, to be used as default gateway
# POT_EXTIF=em0
# The list of extra network interface, to make other network segments accessible
# POT_EXTRA_EXTIF=vlan20 vlan50
# for each extra interface, a variable is used to sepcify its network segment
# POT_NETWORK_vlan20=192.168.100.0/24
# POT_NETWORK_vlan50=10.50.50.0/24
# Do not allow bridge-based pots to forward traffic to each other
# POT_ISOLATE_VNET_POTS=true
# DNS on the Internal Virtual Network
# name of the pot running the DNS
# POT_DNS_NAME=dns
# IP of the DNS
# POT_DNS_IP=10.192.0.2
# Path to default public key to verify pot signatures using signify(1)
# on import/prepare - can be overridden using `-C pubkey`.
# POT_DEFAULT_SIGNATURE_PUBKEY=/usr/local/etc/pot/sign_key.pub
# VPN support
# name of the tunnel network interface
# POT_VPN_EXTIF=tun0
# POT_VPN_NETWORKS=192.168.0.0/24 192.168.10.0/24
================================================
FILE: etc/pot/pot.default.conf
================================================
# pot configuration file - default values
# All datasets related to pot use the some zfs dataset as parent
# With this variable, you can choose which dataset has to be used
POT_ZFS_ROOT=zroot/pot
# It is also important to know where the root dataset is mounted
POT_FS_ROOT=/opt/pot
# This is the cache used to import/export pots
POT_CACHE=/var/cache/pot
# This is where pot is going to store temporary files
POT_TMP=/tmp
# This is the group owning POT_FS_ROOT
POT_GROUP=pot
# This is the suffix added to temporary files created using mktemp,
# X is a placeholder for a random character, see mktemp(1)
POT_MKTEMP_SUFFIX=.XXXXXXXX
# Define the max length of the hostname inside the pot
POT_HOSTNAME_MAX_LENGTH=64
# Internal Virtual Network configuration
# IPv4 Internal Virtual network
POT_NETWORK=10.192.0.0/10
# Internal Virtual Network netmask
POT_NETMASK=255.192.0.0
# The default gateway of the Internal Virtual Network
POT_GATEWAY=10.192.0.1
# The name of the network physical interface, to be used as default gateway
POT_EXTIF=em0
# Additional network interfaces
POT_EXTRA_EXTIF=
# If not empty, it will use this IPv4 on POT_EXTIF as defualt gateway
POT_EXTIF_ADDR=
# Three possible values: ipv4, ipv6, dual
POT_NETWORK_STACK=ipv4
# DNS on the Internal Virtual Network
# name of the pot running the DNS
POT_DNS_NAME=dns
# IP of the DNS
POT_DNS_IP=10.192.0.2
# If set to true, isolate pot vnet bridge members
# (by using `ifconfig <bridgeif> private <memberif>`, see ifconfig(8))
POT_ISOLATE_VNET_POTS=false
# If not empty, this script will be called by pot and the pf rules
# returned on stdout will be loaded into "pot-rdr/anchor" instead
# of those which pot would usually create. This also skips
# creation of netcat-based localhost-tunnels.
# Only works with IPv4 at the moment.
#
# Parameters sent to the script are:
# POT_EXTIF BRIDGE POT_NETWORK POT_GATEWAY proto host_port pot_ip pot_port
# Example:
# igb0 bridge1 10.192.0.0/10 10.192.0.1 tcp 32732 10.192.0.10 80
POT_EXPORT_PORTS_PF_RULES_HOOK=
# VPN support
# Path to default public key to verify pot signatures using signify(1)
# on import/prepare - can be overridden using `-C pubkey`.
POT_DEFAULT_SIGNATURE_PUBKEY=
# name of the tunnel network interface
POT_VPN_EXTIF=
POT_VPN_NETWORKS=
# POT log facility
POT_LOG_FACILITY=local2
================================================
FILE: etc/rc.d/pot
================================================
#!/bin/sh
# PROVIDE: pot
# REQUIRE: NETWORKING LOGIN FILESYSTEM
# BEFORE: securelevel
# KEYWORD: shutdown nojail
. /etc/rc.subr
PATH=$PATH:/usr/local/bin
name="pot"
desc="Pot containers"
procname="pot"
rcvar=pot_enable
start_cmd="pot_start"
stop_cmd="pot_stop"
restart_cmd="pot_restart"
status_cmd="pot_status"
start_precmd="pot_deprecated_start"
stop_postcmd="pot_deprecated_stop"
load_rc_config $name
: ${pot_enable:=NO}
pot_start()
{
local _pname _dyn_pot_list _start
_dyn_pot_list=$(/usr/local/bin/pot ls -q)
for _pname in $_dyn_pot_list ; do
if [ "$( /usr/local/bin/pot get-attr -p "$_pname" -A start-at-boot -q )" = "YES" ]; then
/usr/local/bin/pot start "$_pname"
fi
done
}
pot_stop()
{
local _pname _dyn_pot_list _start
_dyn_pot_list=$(/usr/local/bin/pot ls -q)
for _pname in $_dyn_pot_list ; do
if [ "$( /usr/local/bin/pot get-attr -p "$_pname" -A start-at-boot -q )" = "YES" ]; then
/usr/local/bin/pot stop "$_pname"
fi
done
}
pot_early_start()
{
local _pname _dyn_pot_list _start
_dyn_pot_list=$(/usr/local/bin/pot ls -q)
for _pname in $_dyn_pot_list ; do
if [ "$( /usr/local/bin/pot get-attr -p "$_pname" -A early-start-at-boot -q )" = "YES" ]; then
/usr/local/bin/pot start "$_pname"
fi
done
}
pot_early_stop()
{
local _pname _dyn_pot_list _start
_dyn_pot_list=$(/usr/local/bin/pot ls -q)
for _pname in $_dyn_pot_list ; do
if [ "$( /usr/local/bin/pot get-attr -p "$_pname" -A early-start-at-boot -q )" = "YES" ]; then
/usr/local/bin/pot stop "$_pname"
fi
done
}
pot_restart()
{
pot_stop
pot_early_stop
sleep 5
pot_early_start
pot_start
}
pot_status()
{
local _pname _dyn_pot_list
_dyn_pot_list=$(/usr/local/bin/pot ls -q)
for _pname in $_dyn_pot_list ; do
if [ "$( /usr/local/bin/pot get-attr -p "$_pname" -A early-start-at-boot -q )" = "YES" ] ||
[ "$( /usr/local/bin/pot get-attr -p "$_pname" -A start-at-boot -q )" = "YES" ]; then
if /usr/local/bin/pot info -qrp "$_pname" ; then
echo "pot $_pname is up and running"
else
echo "pot $_pname is not running"
fi
fi
done
}
run_rc_command "$1"
================================================
FILE: etc/rc.d/pot_early
================================================
#!/bin/sh
# PROVIDE: pot_early
# REQUIRE: NETWORKING syslogd pf
# BEFORE: ntpdate
# KEYWORD: shutdown nojail
. /etc/rc.subr
PATH=$PATH:/usr/local/bin
name="pot_early"
desc="Pot containers - early start"
procname="pot"
rcvar=pot_enable
start_cmd="pot_early_start"
stop_cmd="pot_early_stop"
load_rc_config $name
: ${pot_enable:=NO}
pot_early_start()
{
local _pname _dyn_pot_list _start
_dyn_pot_list=$(/usr/local/bin/pot ls -q)
for _pname in $_dyn_pot_list ; do
if [ "$( /usr/local/bin/pot get-attr -p "$_pname" -A early-start-at-boot -q )" = "YES" ]; then
/usr/local/bin/pot start "$_pname"
fi
done
}
pot_early_stop()
{
local _pname _dyn_pot_list _start
_dyn_pot_list=$(/usr/local/bin/pot ls -q)
for _pname in $_dyn_pot_list ; do
if [ "$( /usr/local/bin/pot get-attr -p "$_pname" -A early-start-at-boot -q )" = "YES" ]; then
/usr/local/bin/pot stop "$_pname"
fi
done
}
run_rc_command "$1"
================================================
FILE: release.sh
================================================
#!/bin/sh
print_syntax() { echo "$0" X.Y.Z ; exit "${1:-1}"; }
if [ -z "$1" ]; then
print_syntax
fi
if [ "$1" = "$(echo "$1" | sed -E 's/[0-9]+(\.[0-9]+)+//')" ]; then
echo invalid verion number $1
print_syntax
exit
fi
version="$1"
tag_date="$(date +%Y-%m-%d)"
echo applying new version "$version" with date "$tag_date"
sed -i '' "s/^_POT_VERSION=.*$/_POT_VERSION=$version/" 'bin/pot'
sed -i '' 's/^## \[Unreleased\]/## \[Unreleased\]\
\
### NEWVERSION/' CHANGELOG.md
sed -i '' "s/### NEWVERSION/## \[$version\] $tag_date/" CHANGELOG.md
sed -i '' "s/^version = .*$/version = \"$version\"/" 'share/doc/pot/conf.py'
sed -i '' "s/^release = .*$/release = \"$version\"/" 'share/doc/pot/conf.py'
git diff -p --stat
================================================
FILE: share/doc/pot/.gitignore
================================================
_build
================================================
FILE: share/doc/pot/Description.md
================================================
DESCRIPTION
-----------
Another container framework based on jails, to run FreeBSD containers on
FreeBSD. Every running instance is called "pot", but less flexible than a
VM. It's heavily based on FreeBSD, in particular on jails, ZFS, pf and
rctl.
================================================
FILE: share/doc/pot/Images.md
================================================
# Using `pot` images
This guide has the ambitious goal of explain how to create `pot` images, a feature that allows `pot` to be used with nomad, but it can be useful in other use cases.
This guide assumes that you have already installed `pot` and you are already familiar with it (installation and quickstart guide).
## What is a `pot` image?
A `pot` image is a binary blob representing the `pot` configuration file and it's file system.
In more detail, it's a compressed archive containing a ZFS snapshot of a file system.
## Create an images `pot`
The fundamental steps to create an image of a `pot` container are:
* create a `pot`
* "customize" the `pot` as needed
* take a snapshot
* export the image
**NOTE** `export` and `import` support `single` type `pot`s. Multi-dataset `pot` are not supported yet.
#### Create a `pot`
A `pot` named `test` can be created using the command `pot create`:
```console
# pot create -p test -b 12.0 -N public-bridge -t single`
```
* `-p test` : the `pot` name
* `-b 12.0` : the FreeBSD release version to be used
* `-t single` : the `pot` type. Only `single` type are supported at the moment for `import`/`export`
* `-N public-bridge` : the network type (it can be changed during `import`, but it can be useful to use a network type that is relevant for the use case)
Once the `pot` named `test` is created, it's possible to :
* customize its configuration (attributes, starting command, and so on)
* enter in it and do whatever is needed, for instance install `nginx`
```console
# pot run test
[...]
root@test:~ # pkg install nginx
[...]
root@test:~ # exit
exit
# pot set-cmd -p test -c "nginx -g 'daemon off;'"
# pot set-attr -p test -A no-rc-script -V ON
# pot set-attr -p test -A persistent -V NO
# pot set-rss -p test -C 1
```
Once you're satisfied with your `pot`, you can stop it and take a snapshot:
```console
# pot stop test
# pot snapshot -p test
```
The snapshot can be now exported as an image, with the command `export`
```console
# pot export -p test -t 1.0
```
* `-t 1.0`: the same image can have multiple version. The option `-t` allows to provide a tag to the image
The `export` command can take quite some time, because of the compression step.
Once the `export` command ends, it generates 2 files:
```console
test_1.0.xz
test_1.0.xz.skein
```
The first file is the image, the second file is a hash file, used by the `import` command to verify the integrity.
#### Snapshots management
The `export` command will create an image if and only if one snapshot is available.
The flag `-A` try to automatically fix the number of available snapshots:
* if 0 snapshots are available, `-A` will automatically invoke `pot snapshot`
* if 2+ snapshots are available, `-A` will automatically invoke `pot purge-snapshots`
The command `pot purge-snapshots` deletes all snapshots, except the last one.
### Images creation automated with flavours
Flavour is the way we currently provide to automate the customization of a `pot`.
With flavour, it's possible to automatically:
* apply configuration parameters to your `pot`
* execute a bootstrap script
just putting some files in flavour folder (`/usr/local/etc/pot/flavours`).
In the example above, we customized the `pot` `test` via:
```console
# pot run test
[...]
root@test:~ # pkg install nginx
[...]
root@test:~ # exit
exit
# pot set-cmd -p test -c "nginx -g 'daemon off;'"
# pot set-attr -p test -A no-rc-script -V ON
# pot set-attr -p test -A persistent -V NO
# pot set-rss -p test -C 1
```
Now we automate those commands in a flavour, called `nginx-test`.
In the flavour folder we create one file for the `pot` configuration:
```console
# cat /usr/local/etc/pot/flavours/nginx-test
set-cmd -c "nginx -g 'daemon off;'"
set-attribute -A no-rc-script -V YES
set-attribute -A persistent -V NO
set-rss -C 1
```
The bootstrap script, that will be executed inside the jail, would look like this:
```console
# chmode a+x /usr/local/etc/pot/flavours/nginx-test.sh
# cat /usr/local/etc/pot/flavours/nginx-test.sh
#!/bin/sh
[ -w /etc/pkg/FreeBSD.conf ] && sed -i '' 's/quarterly/latest/' /etc/pkg/FreeBSD.conf
ASSUME_ALWAYS_YES=yes pkg bootstrap
touch /etc/rc.conf
sysrc sendmail_enable="NONE"
pkg install -y nginx
pkg clean -y
```
The flavour `nginx-test` can now be used with the `create` command:
```console
# pot create -p test-flavour -b 12.0 -N public-bridge -t single -f nginx-test
```
An important note: while the bootstrap script is a shell script, where you can do whatever you want, the `pot` command usable in a flavour are a small subset:
* `add-dep`
* `export-ports`
* `copy-in`
* `mount-in`
* `set-attribute` (the abbreviated form `set-attr` is not recognized here)
* `set-cmd`
* `set-env`
* `set-rss`
**NOTE** the `mount-in` command has to be used carefully. If the `pot` will be migrated to a different machine, the folders or the ZFS datasets has to be manually migrated as well
### Images registry and import
Once an image is created, we've seen it can be exported:
```console
# pot export -p test -t 1.0
# ls
test_1.0.xz
test_1.0.xz.skein
```
The image freshly created can now be used to create new `pot` via the command `import`:
```console
# pot import -p test -t 1.0 -U file:///path/to/images
===> importing test @ 1.0 as test_1_0
/var/cache/pot/test_1.0.xz 174 MB 527 MBps 00s
/var/cache/pot/test_1.0.xz.skein 257 B 598 kBps 00s
===> Assigning new IP: 10.192.0.15
```
* `-p potname` : the name of the pot to be imported
* `-t tag`: the version of the image to be imported
* `-U URL`: the base URL to be used to download the `pot` image
The command, when executed, will download the image from the URL (caching them to `/var/cache/pot` and create a new `pot` called `test_1_0` using that image as file system:
```console
# pot info -vp test_1_0
pot name : test_1_0
type : single
base : 12.0
level : 0
network_type : public-bridge
ip : 10.192.0.15
no ports exported
active : false
datasets:
test_1_0/m
snapshots:
zroot/pot/jails/test_1_0@1569922467
zroot/pot/jails/test_1_0/m@1569922467
attributes:
start-at-boot: NO
persistent: NO
no-rc-script: YES
procfs: NO
fdescfs: NO
prunable: NO
localhost-tunnel: NO
to-be-pruned: NO
resource limits:
max amount cpus: 1
```
The `import` process automatically recognizes that the `pot` uses the `prublic-bridge` and assigns a new available IP to the imported `pot`
================================================
FILE: share/doc/pot/Installation.md
================================================
# `pot` installation guide
This is a guide to prepare your FreeBSD installation to use the `pot` jail framework.
**NOTE**: 99% of the operations needs `root` privileges. In this guide, we consider to be logged in as `root`
**NOTE2**: ZFS is mandatory, so if you don't know what it is or you don't have a ZFS pool, please consider to read this [quick guide](https://www.freebsd.org/doc/handbook/zfs-quickstart.html).
## FreeBSD version
`pot` is mainly developed on CURRENT, but it's tested and used on 12.0.
Those two are the versions suggested.
It should work also on 11.3, even if the kernel has to be rebuild, to activate VNET(9), via the VIMAGE option.
If you want to use FreeBSD 11.3, please follow the instruction reported [here](https://www.freebsd.org/doc/handbook/kernelconfig.html) to build a custom kernel with the VIMAGE option enabled.
## Install `pot`
`pot` is available as package or port.
The suggested way is to install it using the packages:
```console
# pkg install -y pot
```
All dependencies will be automatically installed (if not yet present)
If you want to install it using ports, you can
```console
# cd /usr/ports/sysutils/pot
# make install clean
```
**NOTE** A dependency of `pot`, called `potnet` is written in Rust. If you install `potnet` via ports, the build dependencies will be built as well, and it can take really long time (depending on the power of you system, it could be several hours).
## Enable the resource limit database
One really useful feature, needed to improve the isolation between jail, is the resource limit database.
This feature is normally disabled (it seems it causes a performance penalty), and it can be enabled only at boot.
To do so:
```console
# echo kern.racct.enable=1 >> /boot/loader.conf
# reboot
```
This settings will take effect at the next reboot.
#### Known issue
We have found a performance issue with the `vtnet` driver.
If you are installing `pot` on a VM using `vtnet`, probably you want to add this line to your `/boot/loader.conf`:
```console
echo hw.vtnet.lro_disable=1 >> /boot/loader.conf
```
This settings will take effect at the next reboot.
## `pot` framework configuration
Under the folder `/usr/local/etc/pot` you'll find two files:
* `pot.default.conf`
* `pot.conf`
The `pot.default.conf` contains all the default values and it shouldn't be touched.
All needed changes can be made in the `pot.conf` file.
This configuration file provide already a brief explanation for all paramaters, but here we go deep, explaining them one by one
### File system parameters
`pot` is based on ZFS. In the configuration file, 2 parameters are used to let `pot` use your ZFS pool correctly.
#### `POT_ZFS_ROOT` (default `zroot/pot`)
This paramater is the ZFS dataset that will be used by `pot` to store whatever will be needed: jails file systems, bases, and so on.
If the dataset doesn't exist, it will be created by the initialization command (See the last chapter).
#### `POT_FS_ROOT` (default `/opt/pot`)
This parameter is the mountpoint for the `POT_ZFS_ROOT` dataset. You shouldn't use a mountpoint that exists and contains file, otherwise the content will become unreachable.
#### `POT_CACHE` (default `/var/cache/pot`)
This parameter specifies the mountpoint of the dataset `POT_ZFS_ROOT/cache`. This dataset is used only to store `pot` images for the `import` and the `prepare`command. The default value is the suggested one.
### Network parameters
In order to use network types like `alias` or `public-bridge`, some configuration parameters are needed.
#### `POT_EXTIF` (default `em0`)
Currently, `pot` assumes that all the network traffic is going through one physical network interface.
This parameter configures `pot` to use the specified network interface.
It's relevant for `alias`, `public-bridge` and `private-bridge` network type.
#### `POT_NETWORK` (default `10.192.0.0/10`)
This parameter specifies the IPv4 address of you internal virtual network and is used by the `public-bridge` network type only.
It's wise to choose a private network segment that doesn't conflict with your current network setup.
The default address space is huge, however you can choose the network range that match your needs.
#### `POT_NETMASK` (default `255.192.0.0`)
This parameter specifies the netmask relative to the `POT_NETWORK`.
Theoretically, the netmask can be derived by the `POT_NETWORK`. For now, this is not the case, so you have to provide a netmask consistent with the network specified in `POT_NETWORK`
#### `POT_GATEWAY` (default `10.192.0.1`)
This parameter specifies the IP address that will be used as default gateway in your internal virtual network. It has to be part of the network specified in `POT_NETWORK` and it will be used as default gateway for all `pot`s attached to the internal virtual network (`public-bridge` network type).
#### `POT_EXTRA_EXTIF` (default empty)
In case your host has multiple network interfaces connected to multiple network segments, this option allows your `pot`s to access those network segments.
For example, let's say that you have 2 vlan interfaces, called `vlan20` and `vlan30`.
`vlan20` is configured as 10.0.20.4/24
`vlan30` is configured as 10.0.30.8/24
To make those segments accessible, the configuration file should look like:
```
POT_EXTRA_EXTIF=vlan20 vlan30
POT_NETWORK_vlan20=10.0.20.0/24
POT_NETWORK_vlan30=10.0.30.0/24
```
Currently there is no way to use additional external interface for the network type `alias`.
All other network types are supported
#### Network validation
If you want to check that your network configuration is valid, you can use the utility `potnet`:
```console
# potnet config-check
```
This command will show only the errors.
### Experimental parameters
There are other parameters that are used by some experimental features.
#### dns `pot`
An experimental feature is to provide an internal dns service running in a `pot` attached to the internal virtual network.
The dns is still a work in progress, however two parameters are already present for this feature:
* `POT_DNS_NAME`: this parameter specifies the name of the `pot` that will run the dns; default => `dns`
* `POT_DNS_IP`: this parameter specifies the IP (internal to the `POT_NETWORK` that the "dns `pot`" will have; default => `10.192.0.2`
#### VPN support
If your host system is using a VPN to reach some network segments, you can add some parameters in order to be able to connect your internal virtual network to those networks
* `POT_VPN_EXTIF`: the name of the network interface of the VPN software tunnel; default: `tun0`
* `POT_VPN_NETWORKS`: a list of all network segments served by the VPN; default: `192.168.0.0/16`
If you have multiple network segments, you have to list them all. For instance:
```sh
POT_VPN_NETWORKS="192.168.0.0/24 192.168.10.0/24 10.10.0.0/16"
```
## Initialize the environment
The initialization of the environment will:
* Create the ZFS datasets
* Validate the network parameters
* Configure `pf(4)` to be aware of the internal virtual network
If you are already using `pf`, I suggest to make a backup of you `pf` configuration file.
When ready, you can initialize the environment with the command (use the flag `-v` if you want a bit more of verbosity):
```console
# pot init
```
### Initialize and test the internal virtual network
The internal virtual network is not always active, but it's automatically activated if a `pot` configured to use it get started.
However, a command is provided to activate the virtual network:
```console
# pot vnet-start
```
From your host, you can now ping the virtual network default gateway (always reachable from the host):
```console
# ping 10.192.0.1
```
## Remove the `pot` environment
In order to remove the `pot` from your system, a command is provided to make it easy:
```console
# pot de-init
```
This powerful command will remove everything related to `pot` and it cannot be undone.
Even if not mandatory, it would be nice to know why you removed it.
Please, consider to write a feedback email to pizzamig at FreeBSD dot org
* What's wrong with `pot`?
* What's the missing feature I really need?
* How bad is to use it? How can it be more user-friendly?
================================================
FILE: share/doc/pot/Makefile
================================================
# Minimal makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
SPHINXPROJ = pot
SOURCEDIR = .
BUILDDIR = _build
# Put it first so that "make" without argument is like "make help".
help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
.PHONY: help Makefile
# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
================================================
FILE: share/doc/pot/QuickStart.md
================================================
# QuickStart Guide on `pot`
This is an introduction at the usage of `pot`, a `jail(8)` wrapper based on ZFS and `pf(4)` that naively tries to emulate containerization on FreeBSD.
`pot` uses FreeBSD specific technologies, so you need a FreeBSD machine to run it.
**NOTE**: 99% of the operations needs `root` privileges. In this guide, we consider to be logged in as `root`
**NOTE2**: ZFS is mandatory, so if you don't know what it is or you don't have a ZFS pool, please consider to read this [quick guide](https://www.freebsd.org/doc/handbook/zfs-quickstart.html).
**NOTE3**: Some features, like memory limits and memory usage, rely on the resources limit framework, normally disabled. Even if it's not mandatory, it's suggested to enable it, with the following steps:
```console
# echo kern.racct.enable=1 >> /boot/loader.conf
```
This settings will take effect at the next reboot.
**NOTE4**: One of the 3 network configuration need `VNET(9)`, the network subsystem virtualization infrastructure, enabled in the kernel.
On FreeBSD 12 and later, this kernel feature is already enabled and you don't need to do anything.
On FreeBSD 11.x, you have to rebuild the kernel, enabling the VIMAGE options, following the instruction reported [here](https://www.freebsd.org/doc/handbook/kernelconfig.html)
## Install `pot`
The installation process is pretty straightforward:
```console
# pkg install -y pot
```
That's it, `pot` and its dependencies are installed, but we're not yet ready.
#### Configuration [Optional]
Under the folder `/usr/local/etc/pot` you'll find two files:
* `pot.default.conf`
* `pot.conf`
The `pot.default.conf` contains all the default values and it shouldn't be touched.
All needed changes have to be stored in the `pot.conf` file. Please take your time to give a look to this file and to change configuration accordingly to your system
### Initialization
When you are happy with your configuration file, especially with the location of `POT_ZFS_ROOT`, you can run:
```console
# pot init
```
This command will just create the needed ZFS datasets.
## Create a simple `pot`
We can now create the simplest `pot`
```console
# pot create -p mypot -t single -b 11.3
```
**NOTE** The FreeBSD machine doesn't have to be the same version of your `pot` (jail). However, the hosting machine's version has to be greater or equal than the `pot`'s one.
For instance, you can run a FreeBSD 10.4 `pot` on a FreeBSD 11.3 host. You **cannot** run a FreeBSD 12 `pot` on a FreeBSD 11.3 host.
So, we created a `pot`, named `mypot`, based on FreeBSD 11.3 consisting of one ZFS dataset.
Now you can start it or stop it, via:
```console
# pot start mypot
# pot stop mypot
```
If you want to have a shell inside your pot:
```console
# pot term mypot
# pot run mypot # an alias for start+term
```
## A bit of diagnostic
Via the command:
```console
# pot ls
# pot ls -v # more information
```
You can see a list of the `pot`s available on you local machine. The verbose output would look like this:
```console
pot name : mypot
ip4 : inherit
active : true
base : 11.3
level : 0
datasets:
snapshot:
```
If you want to get some information on a specific `pot`, this command is more useful:
```console
# pot info -v -p mypot
pot name : mypot
type : single
base : 11.3
level : 0
ip4 : inherit
active : true
datasets:
mypot/m
snapshot:
attributes:
start-at-boot: NO
persistent: YES
no-rc-script: NO
procfs: NO
prunable: NO
```
Some explanation of this output:
* `type`: currently two types of `pot` are supported: `single`, based on one ZFS dataset, and `multi`, based on multiple ZFS dataset.
* `base`: the FreeBSD version used to build this `pot`.
* `level`: for single type `pot` the level is always `0`. Levels are explained for the multi type `pot`.
* `ip4`: the IPv4 address of the `pot` or the keyword `inherit`. By default, `inherit` is chosen, that means that this `pot` is sharing the same network stack of the running machine.
* `active`: it's a boolean value, that tells you if your `pot` is running or not.
* `datasets`: single type `pot`s have only one dataset.
* `snapshot`: the list of snapshots of this `pot`; currently empty.
* `attributes`: attributes/properties of this this `pot`
If your `pot` is running, runtime information can be obtained via:
```console
# pot start mypot
# pot show -p mypot
pot mypot
disk usage : 274M
virtual memory : 13M
physical memory : 4820K
```
This command will show the current amount of resources used by this `pot`
## Take a snapshot of your `pot`
Thanks to ZFS, taking a snapshot of your stopped `pot` is easy and super fast:
```console
# pot stop mypot
# pot snap mypot
# pot info -v -p mypot
[..]
snapshot:
zroot/pot/jails/mypot@1539804703
zroot/pot/jails/mypot/m@1539804703
```
The snapshot's name is the Unix epoch and it's used to automatically determine the snapshot's chronological sequence.
Now you can restart it and do some real damage:
```console
# pot run mypot
root@mypot:~ # rm -rf /*
[..]
root@mypot:~ # exit
# pot stop mypot
```
We have deleted almost every file in the `pot`, the pot cannot start again (feel free to try!)
The snapshot can be used to revert all the modifications occurred between the time that the snapshot was taken and now, using the following command:
```console
# pot revert -p mypot
# pot run mypot
```
The revert command will automatically select the newest snapshot available.
## Attach a "volume" to your pot
Let's say that you want to attach a pre-existent "volume" to your `pot`.
There are several way to do that, depending on what your volume is.
### First volume type: fscomp
To support users managing ZFS datasets for `pot`, the concept of `fscomp` (AKA file system component) is introduced.
You can create a file system component in the `pot` ecosystem, that can be attached to one or more `pot`s.
When a `fscomp` is created, the underlaying ZFS dataset is created as well.
To create a `fscomp`, you can run:
```console
# pot create-fscomp -f myfscomp
```
With this command, you have created an empty ZFS dataset, a "volume", that can be attached to one or more `pot`s
A list of available `fscomp`s can be obtained with the command:
```console
# pot ls -f
```
To mount your new `fscomp` to a `pot`, you can use the command:
```console
# pot mount-in -p mypot -f myfscomp -m /mnt
# pot info -p mypot -v
```
The `-m` mandatory option represents the mountpoint (absolute pathname) inside the `pot`.
The advantage of this approach, is that `fscomp` are recognized by the `pot` framework, and a set of features is provided, like snapshot, rollback and clone.
### Second volume type: an already existent dataset
It could happen that you want to attach to a `pot` a pre-existing ZFS dataset and you don't want to create an emtpy `fscomp` and move all data there.
To add and external ZFS dataset, the command would be:
```console
# pot mount-in -p mypot -m /mnt -z zroot/mydataset
```
The only difference is the different option used (`-z` instead of `-f`) and the argument of the option is not a `fscomp` name, but a generic valid ZFS dataset.
### Third volume type: a generic directory
There two ways to make external directories available in a `pot`: mount them or copy them.
The decision to mount or to copy is to the user to take, with obvious pros and cons.
To mount a directory, the command would be:
```console
# pot mount-in -p mypot -m /mnt -d mydir
```
The directory `mydir` will be mounted at `/mnt`
To copy a directory, the command would be:
```console
# pot copy-in -p mypot -s mydir -d /mnt
```
The directory `mydir` (and all its file) will be copied in `/mnt`, creating the directory `/mnt/mydir`
### Forth volume type: a single file
For single files, only the copy option is available.
```console
# pot copy-in -p mypot -s myfile -d /mnt
```
The file `myfile` will be copied in `/mnt`.
### Common consideration
The `mount-in` command will change the configuration of the `pot`; the "volume" will be automatically mounted when the `pot` starts and unmounted when the `pot` stops.
If you run `mount-in` when the `pot` is already running, the "volume" is mounted on the fly.
A "volume" can be used with multiple `pot`s. Potential problems, like concurrent access to the same files, cannot be managed by `pot` and are left to the user.
In order to mitigate concurrency access to the same `fscomp`, the option `-r` is introduced:
```console
# pot mount-in -p mypot-ro -f myfscomp -m /mnt -r
# pot mount-in -p mypot-rw -f myfscomp -m /mnt
```
This option will inform the framework to mount `myfscomp` in `mypot-ro` in read-only mode, while in `mypot-rw` that same `myfscomp` is mounted in read-write mode.
## Network configuration
During the creation phase, it's possible to specify which type of network our `pot` should use.
`pot` supports three different type of network configurations:
* inherit
* alias (IPv4 or IPv6) n the host network interface
* IPv4 address on the public internal virtual network
* IPv4 address on a private internal virtual network
By default, `inherit` is the chosen one.
### Network configuration: inherit
To use the `inherit` network type, a `pot` can be created with the following command:
```console
# pot create -p mypot -t single -b 11.3 -N inherit
```
The option `-N` can be omitted, because `inherit` is the default value.
The `inherit` type means that `mypot` will reuse the same network stack of the host machine.
This network type works pretty well when your `pot` doesn't provide/export any network services, but it uses the network's host as client, like a `pot` created to build applications.
### Network configuration: IPv4 or IPv6 alias
If your host is a network that support static IPs, you can assign one static IP address to your `pot` via this network configuration type.
**NOTE** Be sure that in the `pot` configuration file (`/usr/local/etc/pot/pot.conf`) you have correctly set the variable `POT_EXTIF`; this network interface is the one used to route the network traffic and to assign the IP address.
For example, your system has 192.168.178.20/24 as IP address and your network administrator reserved you the additional IP address 192.168.178.200.
To assing the latter IP address to your `pot` you can create it with the following command:
```console
# pot create -p mypot -t single -b 11.3 -N alias -i 192.168.178.200
# pot start mypot
# pot info -vp mypot
```
The alias 192.168.178.200 will be assigned to the network interface during the start phase.
Now, your `pot` is bound to the address 192.168.178.200
When the `pot` is stopped, the alias will be automatically removed from the inferface.
More information about alias addresses on network interfaces are available in the `man` page of `ifconfig(8)`
### Network configuration: public virtual network bridge
Thanks to `VNET(9)`, `pot` supports an IPv4 virtual network. This network is configured in configuration file (`/usr/local/etc/pot/pot.conf`), so be sure you have it properly configured.
This network type refers to a shared bridge where the public virtual network lives. All `pot`s with this network type will share it. The virtual internal network is connected with the ouside via NAT.
To help the `pot` framework and all users to manage the public virtual network, an additional package is required, normally automatically installed as dependency of the package `pot`. It's also manually installable via:
```console
# pkg install potnet
```
To verify you virtual network configuration, this command can be used:
```console
# potnet show
Network topology:
network : 10.192.0.0
min addr: 10.192.0.0
max addr: 10.255.255.255
Addresses already taken:
10.192.0.0
10.192.0.1 default gateway
10.192.0.2 dns
```
The output is from my configuration (and also the default one), however your address' range can differ, depending on the configuration values you have adopted.
Optionally, you can start the virtual network via the command:
```console
# pot vnet-start
```
This command will create and configure the network interfaces properly and will activate `pf` to perform NAT on the virtual network.
**NOTE** This command is automatically executed when a `pot` is configured to use the public virtual network. There is no need to run it manually.
The following command will create a `pot` running on the internal network:
```console
# pot create -p mypot -t single -b 11.3 -N public-bridge -i auto
# pot run mypot
root@mypot:~ # ping 1.1.1.1
[..]
root@mypot:~ # exit
# pot stop mypot
```
The `auto` keyword will automatically select an available address in the internal virtual network and it's the default value, hence the `-i` option can be omitted.
Commands like `pot info -p mypot` and `potnet show` will show you exactly which address has been assigned to your `pot`
If you prefer to assign a specific IP address of your virtual network to your `pot`, you can just do:
```console
# pot create -p mypot2 -t single -b 11.3 -N public-bridge -i 10.192.0.10
```
`pot` will verify if the IP address is available and free to be used.
### Network configuration: private virtual network bridge
The public virtual network has the downside that all `pot`s share the same bridge, affecting isolation.
To mitigate this issue, private virtual network has been introduced.
A private virtual network is just a different bridge, that can be used to connect multiple `pot`s, but it's not automatically shared with all `pot`s.
First of all, to use a private virtual network a private bridge has to be created:
```console
# pot create-private-bridge -B mybridge -S 4
```
This command will create a new private bridge, called `mybridge`, with a network segment big enough to connect 4 `pot`s.
Using `potnet` it's possible to check the details of the private bridge via the command:
```console
# potnet show -b mybridge
10.192.0.16 mybridge bridge - network
10.192.0.17 mybridge bridge - gateway
10.192.0.23 mybridge bridge - broadcast
```
The output is from my configuration, however your address' range can differ, depending on the configuration values you have adopted and the network segment available when the bridge is created.
To activate a specific bridge, you can use the command:
```console
# pot vnet-start -B mybridge
```
This command will create and configure the network interfaces properly and will activate `pf` to perform NAT on the virtual network.
**NOTE** This command is automatically executed when a `pot` is configured to use the public virtual network. There is no need to run it manually.
The following command will create a `pot` running on the private internal network:
```console
# pot create -p mypot -t single -b 11.3 -N private-bridge -B mybridge -i auto
# pot run mypot
root@mypot:~ # ping 1.1.1.1
[..]
root@mypot:~ # exit
# pot stop mypot
```
The `auto` keyword will automatically select an available address in the internal virtual network and it's the default value, hence the `-i` option can be omitted.
Commands like `pot info -p mypot` and `potnet show -b mybridge` will show you exactly which address has been assigned to your `pot`
If you prefer to assign a specific IP address of your virtual network to your `pot`, you can just do:
```console
# pot create -p mypot2 -t single -b 11.3 -N private-bridge -B mybridge -i 10.192.0.19
```
`pot` will verify if the IP address is available and free to be used.
### Export network services with the internal network
The virtual network is not visible outside the host machine, becuase it's based on NAT of the pf's NAT.
To make your network services running in your `pot` visible outside the TCP/UDP, desired ports have to be exported/redirected.
`pot` provides a command to tell which port has to be exported.
```console
# pot export-ports -p mypot -e 80 -e 443
```
The `export-ports` command will make available the port 80 and 443 outside the virtual network. At start, `pot` look for an available host port that can be used to redirect the traffic from the host to the virtual network.
To know which port is used, you can use the `show` command:
```console
# pot start mypot
# pot show -p mypot
pot mypot
disk usage : 274M
virtual memory : 13M
physical memory : 4824K
Network port redirection
192.168.178.20 port 1024 -> 10.192.0.3 port 80
192.168.178.20 port 1025 -> 10.192.0.3 port 443
```
To map the network services to a specific port, instead of leaving the decision to `pot`, the following syntax can be used:
```console
# pot export-ports -p mypot -e 80:30080 -e 443:30443
# pot start mypot
# pot show -p mypot
pot mypot
disk usage : 266M
virtual memory : 33M
physical memory : 17M
Network port redirection
192.168.178.20 port 30080 -> 10.192.0.11 port 80
192.168.178.20 port 30443 -> 10.192.0.11 port 443
```
However, there is no guarantee that the choosen ports are available.
================================================
FILE: share/doc/pot/Synopsis.md
================================================
SYNOPSIS
--------
`pot` SUBCOMMAND
================================================
FILE: share/doc/pot/conf.py
================================================
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# pot documentation build configuration file, created by
# sphinx-quickstart on Thu Nov 28 15:41:27 2019.
#
# This file is execfile()d with the current directory set to its
# containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
# import os
# import sys
# sys.path.insert(0, os.path.abspath('.'))
from recommonmark.transform import AutoStructify
# -- General configuration ------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#
# needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = ['sphinx.ext.githubpages', 'recommonmark']
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix(es) of source filenames.
# You can specify multiple suffix as a list of string:
#
# source_suffix = ['.rst', '.md']
source_suffix = '.md'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = 'pot'
copyright = '2019, Luca Pizzamiglio'
author = 'Luca Pizzamiglio'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = "0.16.0"
# The full version, including alpha/beta/rc tags.
release = "0.16.0"
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
language = None
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This patterns also effect to html_static_path and html_extra_path
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# If true, `todo` and `todoList` produce output, else they produce nothing.
todo_include_todos = False
# -- Options for HTML output ----------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
html_theme = 'alabaster'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#
# html_theme_options = {}
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# Custom sidebar templates, must be a dictionary that maps document names
# to template names.
#
# This is required for the alabaster theme
# refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars
html_sidebars = {
'**': [
'relations.html', # needs 'show_related': True theme option to display
'searchbox.html',
]
}
# -- Options for HTMLHelp output ------------------------------------------
# Output file base name for HTML help builder.
htmlhelp_basename = 'potdoc'
# -- Options for LaTeX output ---------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#
# 'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#
# 'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#
# 'preamble': '',
# Latex figure (float) alignment
#
# 'figure_align': 'htbp',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
(master_doc, 'pot.tex', 'pot Documentation',
'Luca Pizzamiglio', 'manual'),
]
# -- Options for manual page output ---------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
(master_doc, 'pot', 'Another container framework based on jails',
[author], 8)
]
# -- Options for Texinfo output -------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
(master_doc, 'pot', 'pot Documentation',
author, 'pot', 'One line description of project.',
'Miscellaneous'),
]
# app setup hook
def setup(app):
app.add_config_value('recommonmark_config', {
'auto_toc_tree_section': 'Contents',
'enable_math': False,
'enable_inline_math': False,
'enable_eval_rst': True,
}, True)
app.add_transform(AutoStructify)
================================================
FILE: share/doc/pot/index.md
================================================
Contents
--------
* [Synopsis](Synopsis.md)
* [Description](Description.md)
* [QuickStart](QuickStart.md)
* [Installation](Installation.md)
* [migration](migration.md)
* [Images](Images.md)
================================================
FILE: share/doc/pot/migration.md
================================================
## Manual migration handbook
### Prerequisite
* testing with single type pot
* a snapshot is already present
### A xz archive of the datasets
* `zfs send -R zroot/pot/jails/mypot@1539804703 | xz > mypot.1539804703.xz`
Some statistics on FreeBSD 12.0
The file systems are accounted for 801MB, lz4 providing 2.23 as compression ration, leaving 383MB on the disk.
xz -9 is extremely slow, using +800MB of RAM and producing an output of 132MB
xz -6 (default) is quite slow, producing an output of 148MB
xz -3 is decently fast, producing an output of 164MB
xz -0 is quite fast, producing an output of 182MB
# Speculation
### A migration process
send the first xz file and combine with the receive
* `xzcat mypot.1539804703.xz | zfs receive ${POT_ZFS_ROOT}/jails/mypot@1539804703
depending on the content of pot.conf and fscomp.conf, get and extract the other datasets propery
In this case:
* xzcat mypot_m.1539804703.xz | zfs receive ${POT_ZFS_ROOT}/jails/mypot/m@1539804703
================================================
FILE: share/pot/add-dep.sh
================================================
#!/bin/sh
# shellcheck disable=SC3033,SC3040,SC3043
:
add-dep-help()
{
cat <<-"EOH"
pot add-dep [-hv] -p potname -P depPot
-h print this help
-v verbose
-p potname : the working pot
-P depPot : the pot to depend on. Will be started automatically
before starting the working pot "potname".
EOH
}
# $1 pot
# $2 depPot
_add_dependency()
{
local _depPot _pname _cdir
_pname="$1"
_depPot="$2"
_cdir=$POT_FS_ROOT/jails/$_pname/conf
echo "pot.depend=$_depPot" >> "$_cdir"/pot.conf
}
pot-add-dep()
{
local _pname _depPot
_depPot=
_pname=
OPTIND=1
while getopts "hvp:P:" _o ; do
case "$_o" in
h)
add-dep-help
return 0
;;
v)
_POT_VERBOSITY=$(( _POT_VERBOSITY + 1))
;;
P)
_depPot="$OPTARG"
;;
p)
_pname="$OPTARG"
;;
*)
add-dep-help
return 1
;;
esac
done
if [ -z "$_pname" ]; then
_error "A pot name is mandatory"
add-dep-help
return 1
fi
if [ -z "$_depPot" ]; then
_error "A dependency pot is mandatory"
add-dep-help
return 1
fi
if [ "$_pname" = "$_depPot" ]; then
_error "a pot cannot be run time dependecy of itself"
add-dep-help
return 1
fi
if ! _is_pot "$_pname" ; then
_error "pot $_pname is not valid"
add-dep-help
return 1
fi
if ! _is_pot "$_depPot" ; then
_error "dependency pot $_depPot is not valid"
add-dep-help
return 1
fi
if ! _is_uid0 ; then
return 1
fi
_add_dependency "$_pname" "$_depPot"
}
================================================
FILE: share/pot/clone-fscomp.sh
================================================
#!/bin/sh
# shellcheck disable=SC3033,SC3040,SC3043
:
clone-fscomp-help()
{
cat <<-"EOH"
pot clone-fscomp [-hv] -f fscomp -F fscomp
-h print this help
-v verbose
-F fscomp : the fscomp to be cloned (mandatory)
-f fscomp : the fscomp name (mandatory)
EOH
}
# $1 new fscomp name
# $2 old fscomp name
_cf_zfs()
{
local _fscomp _cfscomp _fsdset _fsdir _snap
_fscomp=$1
_cfscomp=$2
_fsdset=${POT_ZFS_ROOT}/fscomp
_fsdir=${POT_FS_ROOT}/fscomp
_snap=$( _zfs_last_snap "$_fsdset/$_cfscomp" )
if [ -z "$_snap" ]; then
_error "$_fsdset/$_cfscomp has no snapshots - please take one"
return 1
else
_debug "Cloning $_cfscomp@$_snap into $_fsdset/$_fscomp"
zfs clone -o mountpoint="$_fsdir/$_fscomp" "$_fsdset/$_cfscomp@$_snap" "$_fsdset/$_fscomp"
fi
return 0 # true
}
pot-clone-fscomp()
{
local _fscomp _cfscomp
_fscomp=
_cfscomp=
OPTIND=1
while getopts "hvf:F:" _o ; do
case "$_o" in
h)
clone-fscomp-help
${EXIT} 0
;;
v)
_POT_VERBOSITY=$(( _POT_VERBOSITY + 1))
;;
f)
_fscomp=$OPTARG
;;
F)
_cfscomp=$OPTARG
;;
*)
clone-fscomp-help
${EXIT} 1
;;
esac
done
# parameter validation
if [ -z "$_fscomp" ]; then
_error "fscomp name is missing (option -f)"
clone-fscomp-help
${EXIT} 1
fi
if [ -z "$_cfscomp" ]; then
_error "clonable fscomp name is missing (option -F)"
clone-fscomp-help
${EXIT} 1
fi
if _zfs_dataset_valid "${POT_ZFS_ROOT}/fscomp/$_fscomp" ; then
_error "fscomp $_fscomp already exists"
${EXIT} 1
fi
if ! _zfs_dataset_valid "${POT_ZFS_ROOT}/fscomp/$_cfscomp" ; then
_error "fscomp $_cfscomp doesn't exist"
${EXIT} 1
fi
if ! _is_uid0 ; then
${EXIT} 1
fi
if ! _cf_zfs "$_fscomp" "$_cfscomp" ; then
${EXIT} 1
fi
}
================================================
FILE: share/pot/clone.sh
================================================
#!/bin/sh
# shellcheck disable=SC3033,SC3040,SC3043
:
trap _cj_undo_clone TERM INT
_set_pipefail
clone-help()
{
cat <<-"EOH"
pot clone [-hvF] -p potname -P basepot [-i ipaddr]
-h print this help
-v verbose
-k keep the pot, if clone fails
-P potname : the pot to be cloned (template)
-s snapshot : the snapshot to be used to clone
-p potname : the name of the pot that is created
-f flavour : flavour to be used
-N network-type : new network type of the cloned pot
-i ipaddr : an ip address or the keyword auto (if applicable)
-B bridge-name : the name of the private bridge to be used
-S network-stack : the network stack (ipv4, ipv6 or dual)
-d dns : change pot dns resolver configuration, one of
inherit - inherit from jailhost
pot - the pot configured in POT_DNS_NAME
custom:<file> - copy <file> into pot configuration
off - leave resolver config unaltered
-F : automatically take snapshots of dataset that has none
EOH
}
# $1 pot name
_cj_undo_clone()
{
_POT_VERBOSITY=0
if [ -z "$_cleanup_pname" ]; then
${EXIT} 1
fi
# stop in subshell, so it won't end script execution
(
pot-cmd stop "$_cleanup_pname" >/dev/null 2>&1
)
if [ "$_cleanup_keep" != "YES" ]; then
pot-cmd destroy -Fp "$_cleanup_pname" -q
fi
unset _cleanup_pname
unset _cleanup_keep
${EXIT} 1
}
# $1 pot name
# $2 pot-base name
# $3 auto-snapshot
# $4 custom snapshot tag
_cj_zfs()
{
local _pname _potbase _jdset _pdir _pbdir _pbdset _mnt_p _opt _autosnap _snaptag _pb_type _snap __last_snap
_pname=$1
_potbase=$2
_autosnap="$3"
_snap="$4"
__last_snap=
_jdset=${POT_ZFS_ROOT}/jails/$_pname
_pbdset=${POT_ZFS_ROOT}/jails/$_potbase
_pdir=${POT_FS_ROOT}/jails/$_pname
_pbdir=${POT_FS_ROOT}/jails/$_potbase
_pb_type="$( _get_conf_var "$_potbase" pot.type )"
# Create the main jail zfs dataset
if ! _zfs_dataset_valid "$_jdset" ; then
zfs create "$_jdset"
else
_info "$_jdset exists already"
fi
# Create the conf directory
if [ ! -d "$_pdir/conf" ]; then
_debug "Create conf dir ($_pdir/conf)"
mkdir -p "$_pdir/conf"
fi
if [ -e "$_pdir/conf/fscomp.conf" ]; then
rm -f "$_pdir/conf/fscomp.conf"
fi
_debug "Cloning $_potbase with snap $_snap"
_update_fscomp "$_potbase"
if [ "$_pb_type" = "single" ]; then
_dset="${_pbdset}/m"
if [ -z "$_snap" ]; then
_snap=$( _zfs_last_snap "$_dset" )
fi
if [ -z "$_snap" ]; then
if [ "$_autosnap" = "YES" ]; then
_snaptag="$(date +%s)"
_info "$_dset has no snap - taking a snapshot on the fly with tag $_snaptag"
zfs snapshot "${_dset}@${_snaptag}"
_snap=$_snaptag
else
_error "$_dset has no snap - please take a snapshot of $_potbase"
_cj_undo_clone
return 1 # error
fi
fi
_debug "clone $_dset@$_snap into $_jdset/m"
zfs clone -o mountpoint="$_pdir/m" "$_dset@$_snap" "$_jdset/m"
cp "${_pbdir}/conf/fscomp.conf" "$_pdir/conf/fscomp.conf"
elif [ "$_pb_type" = "multi" ]; then
# Create the root mountpoint
_create_pot_mountpoint "$_pdir/m"
if [ -z "$_snap" ]; then
__last_snap="YES"
fi
while read -r line ; do
_dset=$( echo "$line" | awk '{print $1}' )
_mnt_p=$( echo "$line" | awk '{print $2}' )
_opt=$( echo "$line" | awk '{print $3}' )
# ro components are replicated "as is"
if [ "$_opt" = ro ] ; then
_debug "$_dset ${_mnt_p} $_opt"
echo "$_dset ${_mnt_p} $_opt" >> "$_pdir/conf/fscomp.conf"
else
# managing potbase datasets
if [ "$_dset" != "${_dset##"${_pbdset}"}" ]; then
_dname="${_dset##"${_pbdset}"/}"
if [ "$__last_snap" = "YES" ]; then
_snap=$( _zfs_last_snap "$_dset" )
fi
if [ -z "$_snap" ]; then
if [ "$_autosnap" = "YES" ]; then
_snaptag="$(date +%s)"
_info "$_dset has no snap - taking a snapshot on the fly with tag $_snaptag"
zfs snapshot "${_dset}@${_snaptag}"
_snap=$_snaptag
else
_error "$_dset has no snap - please take a snapshot of $_potbase"
_cj_undo_clone "$_pname"
return 1
fi
fi
if _zfs_exist "$_jdset/$_dname" "$_pdir/$_dname" ; then
_debug "$_dname dataset already cloned"
else
_debug "clone $_dset@$_snap into $_jdset/$_dname"
zfs clone -o mountpoint="$_pdir/$_dname" "$_dset@$_snap" "$_jdset/$_dname"
if [ -z "$_opt" ]; then
_debug "$_jdset/$_dname ${_mnt_p}"
echo "$_jdset/$_dname ${_mnt_p}" >> "$_pdir/conf/fscomp.conf"
else
_debug "$_jdset/$_dname ${_mnt_p} $_opt"
echo "$_jdset/$_dname ${_mnt_p} $_opt" >> "$_pdir/conf/fscomp.conf"
fi
fi
# managing fscomp datasets - the simple way - no clone support for fscomp
elif [ "$_dset" != "${_dset##"${POT_ZFS_ROOT}"/fscomp}" ]; then
_debug "$_dset ${_mnt_p}"
echo "$_dset ${_mnt_p}" >> "$_pdir/conf/fscomp.conf"
else
_error "not able to manage $_dset"
fi
fi
done < "${POT_FS_ROOT}/jails/$_potbase/conf/fscomp.conf"
fi
return 0 # true
}
# $1 pot name
# $2 pot-base name
# $3 network type
# $4 ip
# $5 bridge name
# $6 network stack
# $7 dns
_cj_conf()
{
local _pname _potbase _ip _network_type _bridge_name _stack _dns _potdns
_pname=$1
_potbase=$2
_network_type=$3
_ip=$4
_bridge_name=$5
_stack=$6
_dns=$7
_pdir=${POT_FS_ROOT}/jails/$_pname
_pbdir=${POT_FS_ROOT}/jails/$_potbase
if [ ! -d "$_pdir/conf" ]; then
mkdir -p "$_pdir/conf"
fi
if [ "$_dns" != "${_dns##custom:}" ]; then # if dns is custom:filename
cp "${_dns##custom:}" "$_pdir/conf/resolv.conf" # copy custom dns config to pot config
_potdns=custom
else
_potdns="$_dns"
fi
grep -vE '^(host.hostname|bridge|ip|vnet|network_type|pot.stack|pot.dns)' "$_pbdir/conf/pot.conf" > "$_pdir/conf/pot.conf"
{
echo "host.hostname=\"$( _get_usable_hostname "${_pname}" )\""
echo "pot.stack=$_stack"
echo "network_type=$_network_type"
case "$_network_type" in
"inherit")
echo "vnet=false"
;;
"alias")
echo "vnet=false"
echo "ip=$_ip"
;;
"public-bridge")
echo "vnet=true"
echo "ip=$_ip"
;;
"private-bridge")
echo "vnet=true"
echo "ip=$_ip"
echo "bridge=$_bridge_name"
;;
esac
echo "pot.dns=$_potdns"
} >> "$_pdir/conf/pot.conf"
if [ -e "$_pbdir/conf/prestart.sh" ]; then
cp "$_pbdir/conf/prestart.sh" "$_pdir/conf/prestart.sh"
fi
if [ -e "$_pbdir/conf/prestop.sh" ]; then
cp "$_pbdir/conf/prestop.sh" "$_pdir/conf/prestop.sh"
fi
if [ -e "$_pbdir/conf/poststart.sh" ]; then
cp "$_pbdir/conf/poststart.sh" "$_pdir/conf/poststart.sh"
fi
if [ -e "$_pbdir/conf/poststop.sh" ]; then
cp "$_pbdir/conf/poststop.sh" "$_pdir/conf/poststop.sh"
fi
if [ -e "$_pbdir/conf/resolv.conf" ]; then
cp "$_pbdir/conf/resolv.conf" "$_pdir/conf/resolv.conf"
fi
}
pot-clone()
{
local _pname _ipaddr _potbase _pblvl _autosnap _pb_type _pb_network_type _network_type _bridge_name _network_stack _snap _flv _dns
_pname=
_ipaddr=
_potbase=
_pblvl=0
_autosnap="NO"
_bridge_name=
_network_stack=
_cleanup_keep="NO"
_snap=
_flv=
_dns=
OPTIND=1
while getopts "hvp:i:P:FN:B:S:f:ks:d:" _o ; do
case "$_o" in
h)
clone-help
${EXIT} 0
;;
v)
_POT_VERBOSITY=$(( _POT_VERBOSITY + 1))
;;
k)
_cleanup_keep="YES"
;;
p)
if ! _is_valid_potname "$OPTARG" ; then
_error "$OPTARG is not a valid name for a pot ('.' is the only character not allowed)"
${EXIT} 1
fi
_pname=$OPTARG
;;
N)
# shellcheck disable=SC2086
if ! _is_in_list "$OPTARG" $_POT_NETWORK_TYPES ; then
_error "Network type $OPTARG not recognized"
clone-help
${EXIT} 1
fi
_network_type="$OPTARG"
;;
i)
if [ -z "$_ipaddr" ]; then
_ipaddr="$OPTARG"
else
_ipaddr="$_ipaddr $OPTARG"
fi
;;
P)
_potbase=$OPTARG
;;
s)
_snap=$OPTARG
;;
B)
_bridge_name=$OPTARG
;;
S)
if ! _is_in_list "$OPTARG" "ipv4" "ipv6" "dual" ; then
_error "Network stack $OPTARG not valid"
create-help
${EXIT} 1
fi
_network_stack="$OPTARG"
;;
F)
_autosnap="YES"
;;
f)
if _is_flavour "$OPTARG" ; then
if [ -z "$_flv" ]; then
_flv="$OPTARG"
else
_flv="$_flv $OPTARG"
fi
else
_error "Flavour $OPTARG not found"
_debug "Looking in the flavour dir ${_POT_FLAVOUR_DIR}"
${EXIT} 1
fi
;;
d)
case $OPTARG in
inherit|pot|off)
_dns=$OPTARG
;;
custom:*)
if [ -r "${OPTARG##custom:}" ]; then
_dns=$OPTARG
else
_error "The file ${OPTARG##custom:} is not valid or readable"
${EXIT} 1
fi
;;
*)
_error "'${OPTARG}' is not a valid dns option"
clone-help
${EXIT} 1
esac
;;
*)
clone-help
${EXIT} 1
;;
esac
done
if [ -z "$_pname" ]; then
_error "pot name is missing (option -p)"
clone-help
${EXIT} 1
fi
if [ -z "$_potbase" ]; then
_error "reference pot name is missing (option -P)"
clone-help
${EXIT} 1
fi
if ! _is_pot "$_potbase" quiet ; then
_error "reference pot $_potbase not found"
clone-help
${EXIT} 1
fi
if _is_pot "$_pname" quiet ; then
_error "pot $_pname already exists"
clone-help
${EXIT} 1
fi
if [ -n "$_snap" ]; then
if [ "$_autosnap" = "YES" ]; then
_error "-s and -F are incompatible - which snapshot should I use"
clone-help
${EXIT} 1
fi
# shellcheck disable=SC2046
if ! _is_in_list "$_snap" $(_get_pot_snaps "$_potbase" | tr '\n' ' ') ; then
_error "snapshot $_snap not found"
_debug "snapshots available $(_get_pot_snaps "$_potbase" | tr '\n' ' ')"
clone-help
${EXIT} 1
fi
fi
if [ -z "$_network_type" ]; then
_pb_network_type="$( _get_pot_network_type "$_potbase" )"
if [ -z "$_pb_network_type" ] ; then
_error "Configuration file for $_potbase contains obsolete elements"
_error "Please run pot update-config -p $_potbase to fix"
${EXIT} 1
fi
_network_type="$_pb_network_type"
fi
if [ -z "$_network_stack" ]; then
_network_stack="$( _get_pot_network_stack "$_potbase" )"
fi
if ! _ipaddr="$( _validate_network_param "$_network_type" "$_ipaddr" "$_bridge_name" "$_network_stack" )" ; then
echo "$_ipaddr"
clone-help
${EXIT} 1
fi
if [ -z "$_dns" ]; then
_dns="$(_get_conf_var "$_potbase" pot.dns)"
fi
_pblvl="$( _get_conf_var "$_potbase" pot.level )"
_pb_type="$( _get_conf_var "$_potbase" pot.type )"
if [ "$_pblvl" = "0" ] && [ "$_pb_type" != "single" ]; then
_error "Level 0 pots cannot be cloned"
clone-help
${EXIT} 1
fi
if ! _is_uid0 ; then
${EXIT} 1
fi
export _cleanup_pname="$_pname"
export _cleanup_keep
if ! _cj_zfs "$_pname" "$_potbase" "$_autosnap" "$_snap" ; then
${EXIT} 1
fi
if ! _cj_conf "$_pname" "$_potbase" "$_network_type" "$_ipaddr" "$_bridge_name" "$_network_stack" "$_dns"; then
${EXIT} 1
fi
if [ -n "$_flv" ]; then
for _f in $_flv ; do
if ! _exec_flv "$_pname" "$_f" ; then
_cj_undo_clone
${EXIT} 1
fi
done
fi
unset _cleanup_pname
unset _cleanup_keep
}
================================================
FILE: share/pot/common-flv.sh
================================================
#!/bin/sh
# shellcheck disable=SC3033,SC3040,SC3043
# $1 flavour name
_is_flavour()
{
local _flv_name
_flv_name="$1"
if [ -n "$( _get_flavour_script "$_flv_name" )" ] ||
[ -n "$( _get_flavour_cmd_file "$_flv_name" )" ]; then
return 0 # true
fi
return 1 # false
}
_get_flavour_script()
{
local _flv_name
_flv_name="$1"
if [ -f "$_flv_name" ] && [ "$_flv_name" != "${_flv_name%%.sh}" ]; then ## it's a script path name
echo "$_flv_name"
elif [ -f "$_flv_name.sh" ]; then ## it's a path name
echo "$_flv_name.sh"
elif [ -f "./$_flv_name.sh" ]; then
echo "./$_flv_name.sh"
elif [ -f "${_POT_FLAVOUR_DIR}/$_flv_name.sh" ]; then
echo "${_POT_FLAVOUR_DIR}/$_flv_name.sh"
fi
}
_get_flavour_cmd_file()
{
local _flv_name
_flv_name="$1"
# if the flavor name ends with .sh return immediately
if [ "$_flv_name" != "${_flv_name%%.sh}" ]; then
return
fi
if [ -f "$_flv_name" ] && [ -r "$_flv_name" ]; then ## it's a cmd file path name
echo "$_flv_name"
elif [ -f "./$_flv_name" ] && [ -r "./$_flv_name" ]; then
echo "./$_flv_name"
elif [ -f "${_POT_FLAVOUR_DIR}/$_flv_name" ] || [ -r "${_POT_FLAVOUR_DIR}/$_flv_name" ]; then
echo "${_POT_FLAVOUR_DIR}/$_flv_name"
fi
}
# $1 the cmd
# all other parameter will be ignored
# tested
_is_cmd_flavorable()
{
local _cmd
_cmd=$1
case $_cmd in
add-dep|set-attribute|\
copy-in|copy-in-flv|mount-in|\
set-rss|export-ports|\
set-cmd|set-env)
return 0
;;
esac
return 1 # false
}
# Special version of set-cmd usable only for flavours
# $1 : pot name
# $2 : the set-cmd line in the file
_flv_set_cmd()
{
local _pname _line _cmd
_pname="$1"
_line="$2"
_cmd="${_line#set-cmd -c }"
if [ "$_line" = "$_cmd" ]; then
_error "In flavour only 'set-cmd -c ' is supported"
return 1
fi
_set_command "$_pname" "$_cmd"
}
_exec_flv()
{
local _pname _flv _pdir _flv_cmd_file _flv_script _flv_dir _previous_pwd _persist
_pname=$1
_flv=$2
_pdir=${POT_FS_ROOT}/jails/$_pname
_debug "Flavour: $_flv"
_flv_cmd_file="$( _get_flavour_cmd_file "$_flv" )"
_flv_dir=$(dirname "${_flv_cmd_file}")
if [ -n "${_flv_cmd_file}" ]; then
_debug "Executing $_flv pot commands on $_pname"
while read -r line ; do
# shellcheck disable=SC2086
if _is_cmd_flavorable $line ; then
if [ "$line" != "${line#set-cmd}" ]; then
# workaround for set-cmd / damn quoting and shell scripts
if ! _flv_set_cmd "$_pname" "$line" ; then
return 1
fi
elif [ "$line" != "${line#copy-in-flv}" ]; then
# copy-in relative to flavour dir
_previous_pwd=$PWD
if ! cd "$_flv_dir"; then
_error "Can't chdir to flavour dir $_flv_dir"
return 1
fi
line=$(echo "$line" | sed "s/^copy-in-flv/copy-in/")
if ! pot-cmd $line -p "$_pname" ; then
return 1
fi
if ! cd "$_previous_pwd"; then
_error "Can't chdir to previous pwd $_previous_pwd"
return 1
fi
else
# shellcheck disable=SC2086
if ! pot-cmd $line -p "$_pname" ; then
return 1
fi
fi
else
_error "Flavor $_flv: line $line not valid - ignoring"
fi
done < "${_flv_cmd_file}"
fi
_flv_script="$( _get_flavour_script "$_flv" )"
if [ -n "${_flv_script}" ]; then
_debug "Starting $_pname pot for the initial bootstrap"
_persist="$(_get_conf_var "$_pname" "pot.attr.persistent")"
if [ "$_persist" = "NO" ]; then
_debug "Setting pot $_pname temporarily to persistent"
if ! pot-cmd set-attribute -A persistent -V YES -p "$_pname" ; then
return 1
fi
fi
pot-cmd start "$_pname"
cp -v "${_flv_script}" "$_pdir/m/tmp"
chmod a+x "$_pdir/m/tmp/$(basename "${_flv_script}" )"
_debug "Executing $_flv script on $_pname"
if ! jexec "$_pname" "/tmp/$(basename "${_flv_script}")" "$_pname" ; then
_error "create: flavour $_flv failed (script)"
return 1
fi
pot-cmd stop "$_pname"
if [ "$_persist" = "NO" ]; then
_debug "Reverting pot $_pname to non-persistent"
if ! pot-cmd set-attribute -A persistent -V NO -p "$_pname" ; then
return 1
fi
fi
else
_debug "No shell script available for the flavour $_flv"
fi
}
================================================
FILE: share/pot/common.sh
================================================
#!/bin/sh
# shellcheck disable=SC2034,SC3033,SC3040,SC3043
: "${EXIT:=exit}"
: "${ECHO:=echo}"
: "${SED:=sed}"
_POT_RW_ATTRIBUTES="start-at-boot early-start-at-boot persistent no-rc-script prunable localhost-tunnel no-tmpfs no-etc-hosts"
_POT_RO_ATTRIBUTES="to-be-pruned"
_POT_NETWORK_TYPES="inherit alias public-bridge private-bridge"
# not devfs handles separately
_POT_JAIL_RW_ATTRIBUTES='enforce_statfs mount fdescfs linprocfs nullfs procfs tmpfs zfs raw_sockets sysvshm sysvsem sysvmsg children mlock devfs_ruleset exec_stop stop_timeout'
# N: arg name jail command, T: type of data, D: deafult value
# devfs is always mounted
_POT_DEFAULT_mount_N='allow.mount'
_POT_DEFAULT_mount_T='bool'
_POT_DEFAULT_mount_D='NO'
_POT_DEFAULT_fdescfs_N='mount.fdescfs'
_POT_DEFAULT_fdescfs_T='bool'
_POT_DEFAULT_fdescfs_D='NO'
_POT_DEFAULT_linprocfs_N='allow.mount.linprocfs'
_POT_DEFAULT_linprocfs_T='bool'
_POT_DEFAULT_linprocfs_D='NO'
_POT_DEFAULT_nullfs_N='allow.mount.nullfs'
_POT_DEFAULT_nullfs_T='bool'
_POT_DEFAULT_nullfs_D='NO'
_POT_DEFAULT_procfs_N='mount.procfs'
_POT_DEFAULT_procfs_T='bool'
_POT_DEFAULT_procfs_D='NO'
_POT_DEFAULT_tmpfs_N='allow.mount.tmpfs'
_POT_DEFAULT_tmpfs_T='bool'
_POT_DEFAULT_tmpfs_D='NO'
_POT_DEFAULT_zfs_N='allow.mount.zfs'
_POT_DEFAULT_zfs_T='bool'
_POT_DEFAULT_zfs_D='NO'
_POT_DEFAULT_raw_sockets_N='allow.raw_sockets'
_POT_DEFAULT_raw_sockets_T='bool'
_POT_DEFAULT_raw_sockets_D='NO'
_POT_DEFAULT_sysvshm_N='sysvshm'
_POT_DEFAULT_sysvshm_T='sysvopt'
_POT_DEFAULT_sysvshm_D='new'
_POT_DEFAULT_sysvsem_N='sysvsem'
_POT_DEFAULT_sysvsem_T='sysvopt'
_POT_DEFAULT_sysvsem_D='new'
_POT_DEFAULT_sysvmsg_N='sysvmsg'
_POT_DEFAULT_sysvmsg_T='sysvopt'
_POT_DEFAULT_sysvmsg_D='new'
_POT_DEFAULT_children_N='children.max'
_POT_DEFAULT_children_T='uint'
_POT_DEFAULT_children_D='0'
_POT_DEFAULT_devfs_ruleset_N='devfs_ruleset'
_POT_DEFAULT_devfs_ruleset_T='uint'
_POT_DEFAULT_devfs_ruleset_D='4'
_POT_DEFAULT_mlock_N='allow.mlock'
_POT_DEFAULT_mlock_T='bool'
_POT_DEFAULT_mlock_D='NO'
_POT_DEFAULT_exec_stop_N='exec.stop'
_POT_DEFAULT_exec_stop_T='string'
_POT_DEFAULT_exec_stop_D=''
_POT_DEFAULT_stop_timeout_N='stop.timeout'
_POT_DEFAULT_stop_timeout_T='uint'
_POT_DEFAULT_stop_timeout_D='10'
# 0:everything, 1:chroot+below(poudriere), 2:just chroot(normal jail)
_POT_DEFAULT_enforce_statfs_N='enforce_statfs'
_POT_DEFAULT_enforce_statfs_T='uint'
_POT_DEFAULT_enforce_statfs_D='2'
__POT_MSG_ERR=0
__POT_MSG_INFO=1
__POT_MSG_DBG=2
# $1 severity
_msg()
{
local _sev
_sev=$1
shift
if [ "$_sev" -gt "${_POT_VERBOSITY:-0}" ]; then
return
fi
case $_sev in
"$__POT_MSG_ERR")
echo "###> " "$@"
;;
"$__POT_MSG_INFO")
echo "===> " "$@"
;;
"$__POT_MSG_DBG")
echo "=====> " "$@"
;;
*)
;;
esac
}
_error()
{
_msg $__POT_MSG_ERR "$@"
}
_info()
{
_msg $__POT_MSG_INFO "$@"
}
_debug()
{
_msg $__POT_MSG_DBG "$@"
}
# $1 quiet / no _error message is emitted
_qerror()
{
if [ "$1" != "quiet" ]; then
_error "$@"
fi
}
_set_pipefail()
{
local _major _version
_major="$(sysctl -n kern.osrelease | cut -f 1 -d '.')"
if [ "$_major" -ge "13" ]; then
# shellcheck disable=SC3040
set -o pipefail
return
fi
_version="$(sysctl -n kern.osrelease | cut -f 1 -d '-')"
case "$_version" in
"12.1"|"12.2")
# shellcheck disable=SC3040
set -o pipefail
;;
esac
}
# tested
_is_verbose()
{
if [ "$_POT_VERBOSITY" -gt $__POT_MSG_INFO ]; then
return 0 # true
else
return 1 # false
fi
}
# $1 quiet / no _error messages are emitted (sometimes useful)
_is_uid0()
{
if [ "$(id -u)" = "0" ]; then
return 0 # true
else
_qerror "$1" "This operation needs 'root' privilegies"
return 1 # false
fi
}
# tested
# check if the argument is an absolute pathname
_is_absolute_path()
{
if [ "$1" = "${1#/}" ]; then
return 1 # false
else
return 0 # true
fi
}
# save encoded parameters suitable for use in `set --`
_save_params () {
for i; do
printf %s\\n "$i" |\
sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/"
done
echo " "
}
# get system boot time in seconds since the epoch
_get_system_uptime() {
sysctl -n kern.boottime | sed -e 's/.*[^u]sec = \([0-9]*\).*$/\1/'
}
# check if the argument is a valid boolean value
# if valid, it returns true and it echo a normalized version of the boolean value (YES/NO)
# if not valid, it return false
_normalize_true_false() {
case $1 in
[Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn])
echo YES
return 0 # true
;;
[Nn][Oo]|[Ff][Aa][Ll][Ss][Ee]|[Oo][Ff][Ff])
echo NO
return 0 # true
;;
*)
return 1 # false
esac
}
# validate some values of the configuration files
# $1 quiet / no _error messages are emitted
_conf_check()
{
if [ -z "${POT_ZFS_ROOT}" ]; then
_qerror "$1" "POT_ZFS_ROOT is mandatory"
return 1 # false
fi
if [ -z "${POT_FS_ROOT}" ]; then
_qerror "$1" "POT_FS_ROOT is mandatory"
return 1 # false
fi
if ! getent group "${POT_GROUP:-pot}" >/dev/null 2>&1; then
_qerror "$1" "Group '${POT_GROUP:-pot}' is missing, create it or change POT_GROUP"
return 1 # false
fi
return 0 # true
}
# it checkes that the pot environment is initialized
# $1 quiet / no _error messages are emitted
_is_init()
{
if ! _conf_check "$1" ; then
_qerror "$1" "Configuration not valid, please verify it"
return 1 # false
fi
if ! _zfs_exist "${POT_ZFS_ROOT}" "${POT_FS_ROOT}" ; then
_qerror "$1" "Your system is not initialized, please run pot init"
return 1 # false
fi
if ! _zfs_dataset_valid "${POT_ZFS_ROOT}/bases" || \
! _zfs_dataset_valid "${POT_ZFS_ROOT}/jails" || \
! _zfs_dataset_valid "${POT_ZFS_ROOT}/fscomp" ; then
_qerror "$1" "Your system is not propery initialized, please run pot init to fix it"
fi
}
# check the POT_TMP directory
# if missing, it will initialize it
_is_pot_tmp_dir()
{
local _pot_tmp
_pot_tmp="${POT_TMP:-/tmp}"
if [ ! -d "$_pot_tmp" ]; then
mkdir -p "$_pot_tmp"
fi
if [ ! -d "$_pot_tmp" ]; then
return 1 # false
fi
}
# set status of pot, locks properly
# $1 pot name
# $2 status to set
# $3 interfaces for pot (epaira)
_set_pot_status()
{
local _pname _status _interfaces _verbose _param
_pname=$1
_status=$2
_interfaces=$3
_param=$(_save_params "-p" "$_pname" "-s" "$_status")
if [ -n "$_interfaces" ]; then
_param="$_param"$(_save_params "-i" "$_interfaces")
fi
if [ "$_POT_VERBOSITY" -gt 1 ]; then
_verbose=$(printf -- "-%$(( _POT_VERBOSITY - 1 ))s" |\
tr " " "v")
_param="$_param"$(_save_params "$_verbose")
fi
eval "set -- $_param"
lockf "${POT_TMP:-/tmp}/pot-lock-$_pname" "${_POT_PATHNAME}"\
set-status "$@"
}
# check if the dataset is a dataset name
# $1 the dataset NAME
# tested
_zfs_dataset_valid()
{
[ -z "$1" ] && return 1 # return false
if [ "$1" = "$( zfs list -o name -H "$1" 2> /dev/null)" ]; then
return 0 # true
else
return 1 # false
fi
}
# check if the dataset $1 with the mountpoint $2 exists
# $1 the dataset NAME
# $2 the mountpoint
# tested
_zfs_exist()
{
local _mnt_
[ -z "$2" ] && return 1 # false
if ! _zfs_dataset_valid "$1" ; then
return 1 # false
fi
_mnt_="$(zfs list -H -o mountpoint "$1" 2> /dev/null )"
if [ "$_mnt_" != "$2" ]; then
return 1 # false
fi
return 0 # true
}
# check if the dataset $1 is mounted
# $1 the dataset NAME
_zfs_mounted()
{
if [ "$(zfs get -Ho value mounted "$1")" != "yes" ]; then
return 1; # false
fi
return 0 # true
}
# given a dataset, look for the corresponding mountpoint
# $1 the dataset
_get_zfs_mountpoint()
{
local _mnt_p _dset
_dset=$1
_mnt_p="$( zfs list -o mountpoint -H "$_dset" 2> /dev/null )"
echo "$_mnt_p"
}
# given a mountpoint, look for the corresponding dataset
# $1 the mountpoint
_get_zfs_dataset()
{
local _mnt_p _dset
_mnt_p=$1
_dset=$(zfs list -o name,mountpoint -H 2>/dev/null | awk -v "mntp=${_mnt_p}" '{ if ($2 == mntp) print $1 }')
echo "$_dset"
}
# check if POT_ZFS_ROOT supports given property
# $1 the property to check
_is_zfs_property_supported()
{
local _properties _ret
_properties=$(zfs get -o property all "${POT_ZFS_ROOT}")
_ret=$?
if [ $_ret -ne 0 ]; then
_error "Could not determine if $POT_ZFS_ROOT supports encryption"
return 2 # error
fi
if echo "$_properties" | grep -xq "$1" ; then
return 0 # true
else
return 1 # false
fi
}
# get extra arguments to be added to the zfs receive command.
# Output can be used without addional escaping.
# In case of errors, the returned string will make sure
# the zfs receive command fails in case the called
# didn't check the return value.
#
# Usage:
# zfs receive $(_get_zfs_receive_extra_args) pool/fs
_get_zfs_receive_extra_args()
{
local _ret
_is_zfs_property_supported "encryption"
_ret=$?
case $_ret in
0) # encryption supported
echo "-x encryption"
return 0
;;
1) # encryption not supported
echo ""
return 0
;;
*) # communicate error
echo "-x therewasanerror"
return 1
;;
esac
}
# take a zfs recursive snapshot of a pot
# $1 pot name
_pot_zfs_snap()
{
local _pname _snaptag _dset
_pname=$1
_snaptag="$(date +%s)"
_debug "Take snapshot of $_pname"
zfs snapshot -r "${POT_ZFS_ROOT}/jails/${_pname}@${_snaptag}"
}
# recursively remove the oldest snapshot of a pot
# $1 pot name
_remove_oldest_pot_snap()
{
local _pname _snap _pdset
_pname=$1
_pdset="${POT_ZFS_ROOT}/jails/${_pname}"
_snap="$( _zfs_oldest_snap "$_pdset" )"
if [ -n "$_snap" ]; then
zfs destroy -r "$_pdset@${_snap}"
fi
}
# take a zfs snapshot of all rw dataset found in the fscomp.conf of a pot
# $1 pot name
# DEPRECATED - but still used by create-base
_pot_zfs_snap_full()
{
local _pname _node _opt _snaptag _dset
_pname=$1
_snaptag="$(date +%s)"
_debug "Take snapshot of the full $_pname"
while read -r line ; do
_dset=$( echo "$line" | awk '{print $1}' )
_opt=$( echo "$line" | awk '{print $3}' )
if [ "$_opt" = "ro" ]; then
continue
fi
if _is_absolute_path "$_dset" ; then
_debug "Skip $_dset, it's not a dataset"
else
_debug "snapshot of $_dset"
zfs snapshot "${_dset}@${_snaptag}"
fi
done < "${POT_FS_ROOT}/jails/$_pname/conf/fscomp.conf"
}
# recursively remove the oldest snapshot of a pot
# $1 pot name
_remove_oldest_fscomp_snap()
{
local _fscomp _snap _fdset
_fscomp=$1
_fdset="${POT_ZFS_ROOT}/fscomp/${_fscomp}"
_snap="$( _zfs_oldest_snap "$_fdset" )"
if [ -n "$_snap" ]; then
zfs destroy -r "$_fdset@${_snap}"
fi
}
# take a zfs snapshot of a fscomp
# $1 fscomp name
_fscomp_zfs_snap()
{
local _fscomp _snaptag _dset
_fscomp=$1
_snaptag="$(date +%s)"
_debug "Take snapshot of $_fscomp"
zfs snapshot "${POT_ZFS_ROOT}/fscomp/${_fscomp}@${_snaptag}"
}
# get the last available snapshot of a given dataset
# $1 the dataset name
_zfs_last_snap()
{
local _dset _output
_dset="$1"
if [ -z "$_dset" ]; then
return 1 # false
fi
_output="$(zfs list -d 1 -H -t snapshot "$_dset" | sort -r | cut -d'@' -f2 | cut -f1 | head -n1)"
if [ -z "$_output" ]; then
return 1 # false
fi
echo "${_output}"
return 0 # true
}
# get the oldest available snapshot of a given dataset
# $1 the dataset name
_zfs_oldest_snap()
{
local _dset _output
_dset="$1"
if [ -z "$_dset" ]; then
return 1 # false
fi
_output="$(zfs list -d 1 -H -t snapshot "$_dset" | sort -r | cut -d'@' -f2 | cut -f1 | tail -n1)"
if [ -z "$_output" ]; then
return 1 # false
fi
echo "${_output}"
return 0 # true
}
# get the amount of available snapshots of a given dataset
# $1 the dataset name
_zfs_count_snap()
{
local _dset _output
_dset="$1"
if [ -z "$_dset" ]; then
return 1 # false
fi
_output="$(zfs list -d 1 -H -t snapshot "$_dset" | grep -c . )"
if [ -z "$_output" ]; then
echo 0
fi
echo "${_output}"
}
# check if the snapshot of the pot does exist
# $1 pot name
# $2 snapshot name
_is_zfs_pot_snap()
{
local _pname _snap _dset
_pname=$1
_snap=$2
if zfs list -t snap "${POT_ZFS_ROOT}/jails/${_pname}@${_snap}" 2>/dev/null ; then
return 0 # true
else
return 1 # false
fi
}
# $1 pot name
# tested (common.sh 7)
_get_usable_hostname() {
local _pname _hname _phname
_pname="$1"
_hname="$(hostname)"
if [ ${#_pname} -gt "${POT_HOSTNAME_MAX_LENGTH:-64}" ]; then
echo "$_pname" | awk -v len="${POT_HOSTNAME_MAX_LENGTH:-64}" '{ truncated = substr($1, 1, len); printf("%s", truncated); }'
else
_phname="${_pname}.$_hname"
if [ ${#_phname} -gt "${POT_HOSTNAME_MAX_LENGTH:-64}" ]; then
echo "$_pname"
else
echo "$_phname"
fi
fi
}
# $1 bridge name
# $2 var name
_get_bridge_var()
{
local _Bname _cfile _var _value
_Bname="$1"
_cfile="${POT_FS_ROOT}/bridges/$_Bname"
_var="$2"
_value="$( grep "^$_var=" "$_cfile" | tr -d ' \t"' | cut -f2 -d'=' )"
echo "$_value"
}
# $1 pot name
# $2 var name
_get_conf_var()
{
local _pname _cdir _var _value
_pname="$1"
_cdir="${POT_FS_ROOT}/jails/$_pname/conf"
_var="$2"
_value="$( grep "^$_var=" "$_cdir/pot.conf" | tr -d ' \t"' | cut -f2 -d'=' )"
echo "$_value"
}
# $1 pot name
# $2 var name
_get_conf_var_string()
{
local _pname _cdir _var _value
_pname="$1"
_cdir="${POT_FS_ROOT}/jails/$_pname/conf"
_var="$2"
_value="$( grep "^$_var=" "$_cdir/pot.conf" | cut -f2 -d'=' )"
echo "$_value"
}
# $1 pot name
# $2 var name
_get_ip_var()
{
local _pname _cdir _var _value
_pname="$1"
_cdir="${POT_FS_ROOT}/jails/$_pname/conf"
_value="$( grep "^ip=" "$_cdir/pot.conf" | sed 's/^ip=//' )"
echo "$_value"
}
_get_pot_export_ports()
{
local _pname _cdir _var _value
_pname="$1"
_cdir="${POT_FS_ROOT}/jails/$_pname/conf"
_value="$(awk '/pot.export.ports/ { n=split($0,array,"="); if (n==2) { print array[2]; } }' "$_cdir/pot.conf" )"
echo "$_value"
}
# $1 pot name
_get_pot_base()
{
_get_conf_var "$1" pot.base
}
# $1 pot name
_get_pot_lvl()
{
_get_conf_var "$1" pot.level
}
# $1 pot name
_get_pot_type()
{
local _type
_type="$( _get_conf_var "$1" pot.type )"
if [ -z "$_type" ]; then
_type="multi"
fi
echo "$_type"
}
# $1 pot name
_get_pot_network_type()
{
_get_conf_var "$1" network_type
}
# $1 pot name
_is_ip_inherit()
{
local _pname _val
_pname="$1"
if [ "$(_get_pot_network_type "$_pname" )" = "inherit" ]; then
return 0 # true
else
return 1 # false
fi
}
# $1 pot name
_is_pot_vnet()
{
local _pname _val
_pname="$1"
_val="$( _get_conf_var "$_pname" vnet )"
if [ "$_val" = "true" ]; then
return 0 # true
else
return 1 # false
fi
}
# $1 pot name
_is_pot_prunable()
{
local _pname
_pname="$1"
if [ "$( _get_conf_var "$_pname" "pot.attr.prunable" )" = "YES" ]; then
return 0 # true
else
return 1
fi
}
# $1 bridge name
# $2 quiet / no _error messages are emitted (sometimes useful)
_is_bridge()
{
local _bname _bconf
_bname="$1"
_bconf="${POT_FS_ROOT}/bridges/$_bname"
if [ ! -e "$_bconf" ]; then
_qerror "$2" "bridge $_bname not found"
return 1 # false
fi
return 0 # true
}
# $1 fscomp name
# $2 quiet / no _error messages are emitted (sometimes useful)
# tested
_is_fscomp()
{
local _fscomp _fdir _fdset
_fscomp="$1"
_fdir="${POT_FS_ROOT}/fscomp/$_fscomp"
_fdset="${POT_ZFS_ROOT}/fscomp/$_fscomp"
if [ ! -d "$_fdir" ]; then
_qerror "$2" "fscomp $_fscomp not found"
return 1
fi
if ! _zfs_dataset_valid "$_fdset" ; then
_qerror "$2" "dataset $_fdset for fscomp $_fscomp not found"
return 2
fi
return 0
}
# $1 base name
# $2 quiet / no _error messages are emitted (sometimes useful)
# tested
_is_base()
{
local _base _bdir _bdset
_base="$1"
_bdir="${POT_FS_ROOT}/bases/$_base"
_bdset="${POT_ZFS_ROOT}/bases/$_base"
if [ ! -d "$_bdir" ]; then
if [ "$2" != "quiet" ]; then
_error "Base $_base not found"
fi
return 1 # false
fi
if ! _zfs_dataset_valid "$_bdset" ; then
if [ "$2" != "quiet" ]; then
_error "zfs dataset $_bdset not found"
fi
return 2 #false
fi
return 0 # true
}
# $1 pot name
# $2 quiet / no _error messages are emitted (sometimes useful)
# tested
_is_pot()
{
local _pname _pdir
_pname="$1"
_pdir="${POT_FS_ROOT}/jails/$_pname"
if [ ! -d "$_pdir" ]; then
_qerror "$2" "Pot $_pname not found"
return 1 # false
fi
if ! _zfs_dataset_valid "${POT_ZFS_ROOT}/jails/$_pname" ; then
_qerror "$2" "zfs dataset $_pname not found"
return 2 # false
fi
if [ ! -d "$_pdir/m" ] || [ ! -r "$_pdir/conf/pot.conf" ] ; then
_qerror "$2" "Some component of the pot $_pname is missing"
return 3 # false
fi
if [ "$( _get_pot_type "$_pname" )" = "multi" ] && [ ! -r "$_pdir/conf/fscomp.conf" ]; then
_qerror "$2" "Some component of the pot $_pname is missing"
return 4 # false
fi
return 0 # true
}
# $1 pot name
# tested
_is_pot_running()
{
if [ -z "$1" ]; then
return 1 ## false
fi
jls -j "$1" >/dev/null 2>/dev/null
return $?
}
# $1 pot name
# tested (common1)
_is_valid_potname()
{
if echo "$1" | grep -Fq '.' ; then
return 1 # false
else
return 0 # true
fi
}
# $1 the element to search
# $2.. the list
# tested
_is_in_list()
{
local _e
if [ $# -lt 2 ]; then
return 1 # false
fi
_e="$1"
shift
# shellcheck disable=SC2068
for e in $@ ; do
if [ "$_e" = "$e" ]; then
return 0 # true
fi
done
return 1 # false
}
# $1 the number to test
# tested ( common8 )
_is_natural_number()
{
case "$1" in
''|*[!0-9]*)
return 1 # false
;;
*)
return 0 # true
;;
esac
}
# $1 a string
# tested ( common8 )
_contains_spaces()
{
echo "$1" | grep -q "[[:space:]]"
}
# $1 mountpoint
# tested
_is_mounted()
{
local _mnt_p _mounted
_mnt_p=$1
if [ -z "$_mnt_p" ]; then
return 1 # false
fi
_mounted=$( mount | grep -F "$_mnt_p" | awk '{print $3}')
for m in $_mounted ; do
if [ "$m" = "$_mnt_p" ]; then
return 0 # true
fi
done
return 1 # false
}
# $1 mountpoint
# tested
_umount()
{
local _mnt_p
_mnt_p=$1
if _is_mounted "$_mnt_p" ; then
_debug "unmount $_mnt_p"
umount -f "$_mnt_p"
else
_debug "$_mnt_p is already unmounted"
fi
}
# $1 pot
# $2 cmd
_set_command()
{
local _pname _cmd _cdir _cmd1 _cmd2
_pname="$1"
_cmd="$2"
_cdir=$POT_FS_ROOT/jails/$_pname/conf
sed -i '' -e "/^pot.cmd=.*/d" "$_cdir/pot.conf"
_cmd1="$( echo "$_cmd" | sed 's/^"//' )"
if [ "$_cmd" = "$_cmd1" ]; then
echo "pot.cmd=$_cmd" >> "$_cdir"/pot.conf
else
_cmd2="$( echo "$_cmd1" | sed 's/"$//' )"
echo "pot.cmd=$_cmd2" >> "$_cdir/pot.conf"
fi
}
# tested
_is_rctl_available()
{
local _racct
_racct="$(sysctl -qn kern.racct.enable)"
if [ "$_racct" = "1" ]; then
return 0 # true
fi
return 1 # false
}
_is_vnet_available()
{
if [ "$(sysctl -n kern.features.vimage 2>/dev/null)" = "1" ]; then
return 0 # true
else
return 1 # false
fi
}
_is_potnet_available()
{
if which potnet 2> /dev/null > /dev/null ; then
return 0 # true
else
return 1 # false
fi
}
# tested (common7)
_get_arch()
{
echo "$(sysctl -n hw.machine)-$(sysctl -n hw.machine_arch)"
}
# tested (common7)
_get_valid_releases()
{
local _arch _file_prefix
_file_prefix="$(_get_arch)"
if [ -z "$_file_prefix" ]; then
echo
fi
releases="$( find /usr/local/share/freebsd/MANIFESTS -type f -name "${_file_prefix}-*" | sed s%/usr/local/share/freebsd/MANIFESTS/"${_file_prefix}"-%% | sort -V | sed 's/-RELEASE//' | tr '\n' ' ' )"
echo "$releases"
}
# tested (common7)
_is_valid_release()
{
local _rel _releases
if [ -z "$1" ]; then
return 1 # false
fi
_rel="$1"
_releases="$( _get_valid_releases )"
# shellcheck disable=SC2086
if _is_in_list "$_rel" $_releases ; then
return 0 # true
else
return 1 # false
fi
}
# $1 potname
# it's required to have all the file-system mounted to access /bin/freebsd-version
_get_os_release()
{
local _pname
_pname="$1"
if [ -r "${POT_FS_ROOT}/jails/$_pname/m/bin/freebsd-version" ]; then
grep ^USERLAND "${POT_FS_ROOT}/jails/$_pname/m/bin/freebsd-version" | cut -f 2 -d"=" | tr -d \"
else
_get_conf_var "$_pname" osrelease
fi
}
# $1 FreeBSD release.
# for instance 12.0 or 13.0-RC1
_get_freebsd_release_name()
{
if echo "$1" | grep -q "RC" ; then
echo "$1"
else
echo "$1-RELEASE"
fi
}
_fetch_freebsd()
{
local _archpath _rel
_archpath="$(_get_arch)"
if ! _fetch_freebsd_internal "$1" "$_archpath"; then
# remove artifact and retry only once
_rel="$( _get_freebsd_release_name "$1" )"
rm -f "${POT_CACHE}/${_rel}"_base.txz
if ! _fetch_freebsd_internal "$1" "$_archpath"; then
return 1 # false
fi
return 0 # true
fi
return 0 # true
}
# $1 release, in short format, major.minor or major.minor-RC#
_fetch_freebsd_internal()
{
local _rel _sha _sha_m _archpath
_rel="$( _get_freebsd_release_name "$1" )"
_archpath="$( echo "$2" | sed -e 's:-:/:' )"
if [ ! -r "${POT_CACHE}/${_rel}"_base.txz ]; then
fetch -m https://ftp.freebsd.org/pub/FreeBSD/releases/"$_archpath"/"${_rel}"/base.txz -o "${POT_CACHE}/${_rel}"_base.txz
fi
if [ ! -r "${POT_CACHE}/${_rel}"_base.txz ]; then
return 1 # false
fi
if [ -r /usr/local/share/freebsd/MANIFESTS/"$2"-"${_rel}" ]; then
_sha=$( sha256 -q "${POT_CACHE}/${_rel}"_base.txz )
# shellcheck disable=SC2002
_sha_m=$( cat /usr/local/share/freebsd/MANIFESTS/"$2"-"${_rel}" | awk '/^base.txz/ { print $2 }' )
# This version would remove the useless cat, but the testability of this function is compromised
#_sha_m=$( awk '/^base.txz/ { print $2 }' < /usr/local/share/freebsd/MANIFESTS/"$2"-"${_rel}")
if [ "$_sha" != "$_sha_m" ]; then
_error "sha256 doesn't match! Aborting"
return 1 # false
fi
else
_error "No manifests found - please install the package freebsd-release-manifests"
return 1 # false
fi
return 0 # true
}
# $1 fscomp.conf absolute pathname
_print_pot_fscomp()
{
local _dset _mnt_p
while read -r line ; do
_dset=$( echo "$line" | awk '{print $1}' )
_mnt_p=$( echo "$line" | awk '{print $2}' )
printf "\\t\\t%s => %s\\n" "${_mnt_p##"${POT_FS_ROOT}"/jails/}" "${_dset##"${POT_ZFS_ROOT}"/}"
done < "$1"
}
# $1 pot name
_print_pot_snaps()
{
if [ -z "$( zfs list -t snapshot -o name -Hr "${POT_ZFS_ROOT}/jails/$1")" ]; then
printf "\t\tno snapshots\n"
else
for _s in $( zfs list -t snapshot -o name -Hr "${POT_ZFS_ROOT}/jails/$1" | tr '\n' ' ' ) ; do
printf "\\t\\t%s\\n" "$_s"
done
fi
}
#1 pot name
_get_pot_snaps()
{
for _s in $( zfs list -t snapshot -o name -H "${POT_ZFS_ROOT}/jails/$1" | tr '\n' ' ' ) ; do
echo "${_s##*@}"
done
}
# $1 mountpoint to create (proper permissions are applied)
_create_pot_mountpoint()
{
local _mp
_mp="$1"
if [ ! -d "$_mp" ]; then
_debug "Creating mountpoint $_mp"
mkdir -p "$_mp" || exit 1
fi
}
# $1 pot name
_is_fscomp_old()
{
local _pname _fsconf _mnt_p _stripped_mnt_p
_pname="$1"
_fsconf="${POT_FS_ROOT}/jails/$_pname/conf/fscomp.conf"
while read -r line; do
_mnt_p=$( echo "$line" | awk '{print $2}' )
_stripped_mnt_p="${_mnt_p##"${POT_FS_ROOT}/jails/$_pname/m"}"
if [ "$_stripped_mnt_p" != "$_mnt_p" ]; then
return 0 # true
fi
done < "$_fsconf"
return 1 # false
}
# $1 pot name
_update_fscomp()
{
local _pname _fsconf _mnt_p _stripped_mnt_p _dset _opt _tmpfile
_pname="$1"
if _is_fscomp_old "$_pname" ; then
_fsconf="${POT_FS_ROOT}/jails/$_pname/conf/fscomp.conf"
_tmpfile=$(mktemp "${POT_TMP:-/tmp}/fscomp.conf.${_pname}${POT_MKTEMP_SUFFIX}")
while read -r line; do
_dset=$( echo "$line" | awk '{print $1}' )
_mnt_p=$( echo "$line" | awk '{print $2}' )
_opt=$( echo "$line" | awk '{print $3}' )
_stripped_mnt_p="${_mnt_p##"${POT_FS_ROOT}/jails/$_pname/m"}"
if [ -z "$_stripped_mnt_p" ]; then
_stripped_mnt_p="/"
fi
${ECHO} "$_dset $_stripped_mnt_p $_opt" >> "$_tmpfile"
done < "$_fsconf"
mv "$_tmpfile" "$_fsconf"
fi
}
# $1 pot name
_pot_mount()
{
local _pname _dset _mnt_p _opt _node
_pname="$1"
if ! _is_pot "$_pname" ; then
return 1 # false
fi
_update_fscomp "$_pname"
while read -r line ; do
if [ -z "$line" ]; then
_debug "Empty line found. Skipping."
continue
fi
_dset=$( echo "$line" | awk '{print $1}' )
_mnt_p=$( echo "$line" | awk '{print $2}' )
_mnt_p="${POT_FS_ROOT}/jails/$_pname/m$_mnt_p"
_mnt_p="${_mnt_p%/}"
_opt=$( echo "$line" | awk '{print $3}' )
if [ "$_opt" = "zfs-remount" ]; then
# if the mountpoint doesn't exist, zfs will create it
zfs set mountpoint="$_mnt_p" "$_dset"
_node=$( _get_zfs_mountpoint "$_dset" )
if _zfs_exist "$_dset" "$_node" ; then
# the information are correct - move the mountpoint
_debug "_pot_mount: the dataset $_dset is mounted at $_node"
else
# mountpoint already moved ?
_error "_pot_mount: Dataset $_dset not mounted at $_mnt_p! Aborting"
return 1 # false
fi
else
if _is_absolute_path "$_dset" ; then
if ! mount_nullfs -o "${_opt:-rw}" "$_dset" "$_mnt_p" ; then
_error "Error mounting $_dset on $_mnt_p"
return 1 # false
else
_debug "mount $_mnt_p"
fi
else
_node=$( _get_zfs_mountpoint "$_dset" )
if [ ! -d "$_mnt_p" ]; then
_debug "start: creating the missing mountpoint $_mnt_p"
if ! mkdir "$_mnt_p" ; then
_error "Error creating the missing mountpoint $_mnt_p"
return 1
fi
fi
if ! mount_nullfs -o "${_opt:-rw}" "$_node" "$_mnt_p" ; then
_error "Error mounting $_node"
return 1 # false
else
_debug "mount $_mnt_p"
fi
fi
fi
done < "${POT_FS_ROOT}/jails/$_pname/conf/fscomp.conf"
if [ "$(_get_conf_var "$_pname" pot.attr.no-tmpfs)" = "YES" ]; then
_debug "Not mounting tmpfs because of no-tmppfs attribure"
else
if ! mount -t tmpfs tmpfs "${POT_FS_ROOT}/jails/$_pname/m/tmp" ; then
_error "Error mounting tmpfs"
return 1
else
_debug "mount ${POT_FS_ROOT}/jails/$_pname/m/tmp"
fi
fi
return 0 # true
}
# $1 pot name
_pot_umount()
{
local _pname _tmpfile _jdir _node _mnt_p _opt _dset
_pname="$1"
if ! _tmpfile=$(mktemp -t "${_pname}.XXXXXX") ; then
_error "not able to create temporary file - umount failed"
return 1 # false
fi
_jdir="${POT_FS_ROOT}/jails/$_pname"
if [ "$(_get_conf_var "$_pname" pot.attr.no-tmpfs)" = "YES" ]; then
_debug "Not umounting tmpfs because of no-tmppfs attribure"
else
_umount "$_jdir/m/tmp"
fi
if [ "$(_get_conf_var "$_pname" "pot.attr.fdescfs")" = "YES" ]; then
_umount "$_jdir/m/dev/fs"
fi
_umount "$_jdir/m/dev"
if [ "$(_get_conf_var "$_pname" "pot.attr.procfs")" = "YES" ]; then
_umount "$_jdir/m/proc"
fi
if [ -e "$_jdir/conf/fscomp.conf" ]; then
_update_fscomp "$_pname"
tail -r "$_jdir/conf/fscomp.conf" > "$_tmpfile"
while read -r line ; do
_dset=$( echo "$line" | awk '{print $1}' )
_mnt_p=$( echo "$line" | awk '{print $2}' )
_mnt_p="${POT_FS_ROOT}/jails/$_pname/m$_mnt_p"
_mnt_p=${_mnt_p%/}
_opt=$( echo "$line" | awk '{print $3}' )
if [ "$_opt" = "zfs-remount" ]; then
_node=${POT_FS_ROOT}/jails/$_pname/$(basename "$_dset")
zfs set mountpoint="$_node" "$_dset"
if _zfs_exist "$_dset" "$_node" ; then
# the information are correct - move the mountpoint
_debug "stop: the dataset $_dset is mounted at $_node"
else
# mountpoint not moved
_error "Dataset $_dset moved to $_node (Fix it manually)"
fi
else
_umount "$_mnt_p"
fi
done < "$_tmpfile"
rm "$_tmpfile"
fi
}
_get_pot_list()
{
# shellcheck disable=SC2011
ls -d "${POT_FS_ROOT}/jails/"*/ 2>/dev/null | xargs -I {} basename {} | tr '\n' ' '
}
_get_bridge_list()
{
# shellcheck disable=SC2038
find "${POT_FS_ROOT}/bridges" -type f 2>/dev/null | xargs -I {} basename {} | tr '\n' ' '
}
pot-cmd()
{
local _cmd _func
_cmd=$1
shift
if [ ! -r "${_POT_INCLUDE}/${_cmd}.sh" ]; then
_error "Fatal error! $_cmd implementation not found!"
${EXIT} 1
fi
if [ "$_cmd" != "init" ] && [ "$_cmd" != "de-init" ] && [ "$_cmd" != "version" ] ; then
if [ ! -d "$POT_FS_ROOT" ]; then
>&2 _error "$POT_FS_ROOT does not exist, please run 'pot init'"
${EXIT} 1
fi
if [ ! -r "$POT_FS_ROOT" ]; then
>&2 _error "Current user has no read access to $POT_FS_ROOT"
${EXIT} 1
fi
fi
# shellcheck disable=SC1090
. "${_POT_INCLUDE}/${_cmd}.sh"
_func=pot-${_cmd}
case "$_cmd" in
create|import|clone|create-private-bridge|prepare|copy-in)
if [ "$_POT_RECURSIVE" = "1" ]; then
logger -p "${POT_LOG_FACILITY}".info -t pot "$_func $*"
$_func "$@"
else
export _POT_RECURSIVE=1
lockf -k /tmp/pot-lock-file "$_POT_PATHNAME" "$_cmd" "$@"
fi
;;
config|get-attr|get-rss|info|last-run-stats|list|ps|show|top)
if _is_verbose ; then
logger -p "${POT_LOG_FACILITY}".debug -t pot "$_func $*"
fi
$_func "$@"
;;
*)
logger -p "${POT_LOG_FACILITY}".info -t pot "$_func $*"
$_func "$@"
;;
esac
}
================================================
FILE: share/pot/config.sh
================================================
#!/bin/sh
# shellcheck disable=SC3033,SC3040,SC3043
: "${_config_names:="fs_root zfs_root gateway syslogd pot_prefix fscomp_prefix network_stack"}"
config-help()
{
cat <<-EOH
pot config [-hvq] [-g name]
-h print this help
-v verbose
-q quiet
-g name : get value of config item "name", one of:
$(echo "$_config_names" | xargs -n1 echo " +" | sort)
EOH
}
# $1 quiet
# $2 name
# $3 value
_config_echo()
{
if [ "$1" = "quiet" ]; then
echo "$3"
else
echo "$2 = $3"
fi
}
pot-config()
{
local _quiet
_quiet="NO"
_get=
OPTIND=1
while getopts "hvqg:" _o ; do
case "$_o" in
h)
config-help
${EXIT} 0
;;
v)
_POT_VERBOSITY=$(( _POT_VERBOSITY + 1))
;;
q)
_quiet="quiet"
;;
g)
if _is_in_list "$OPTARG" "$_config_names" ; then
_get="$OPTARG"
else
_qerror $_quiet "$OPTARG is not a valid name"
[ "quiet" != "$_quiet" ] && config-help
${EXIT} 1
fi
;;
?)
config-help
${EXIT} 1
;;
esac
done
if [ -z "$_get" ]; then
_qerror $_quiet "option -g is mandatory"
[ "quiet" != "$_quiet" ] && config-help
${EXIT} 1
fi
case $_get in
fs_root)
_config_echo $_quiet "fs_root" "$POT_FS_ROOT"
;;
zfs_root)
_config_echo $_quiet "zfs_root" "$POT_ZFS_ROOT"
;;
gateway)
_config_echo $_quiet "gateway" "$POT_GATEWAY"
;;
syslogd)
_config_echo $_quiet "syslogd flags" "-b 127.0.0.1 -b $POT_GATEWAY -a $POT_NETWORK"
;;
pot_prefix)
_config_echo $_quiet "pot prefix" "$POT_FS_ROOT/jails"
;;
fscomp_prefix)
_config_echo $_quiet "fscomp prefix" "$POT_FS_ROOT/fscomp"
;;
network_stack)
_config_echo $_quiet "network stack" "$( _get_network_stack )"
;;
esac
}
================================================
FILE: share/pot/copy-in.sh
================================================
#!/bin/sh
# shellcheck disable=SC3033,SC3040,SC3043
:
copy-in-help()
{
cat <<-"EOH"
pot copy-in [-hv] -p pot -s source -d dest
-h print this help
-v verbose
-F force copy operation for running jails
(WARNING: can expose parts of the host file system)
-p pot : the working pot
-s source : the file or directory to be copied in
-d dest : the final location inside the pot
-c create any missing path components to `dirname destination`
inside the pot
EOH
}
# $1 source
_source_validation()
{
local _source
_source="$1"
if [ -f "$_source" ] || [ -d "$_source" ]; then
if [ -r "$_source" ]; then
return 0 # true
else
_error "$_source not readable"
fi
else
_error "$_source not valid"
return 1 # false
fi
}
_make_temp_source()
{
local _proot
_proot="$1"
mktemp -d "$_proot/tmp/copy-in${POT_MKTEMP_SUFFIX}"
}
_mount_source_into_potroot()
{
local _source _mountpoint _source_mnt
_source="$1"
_mountpoint="$2"
if [ -f "$_source" ]; then
_source_mnt="$( dirname "$_source" )"
else
_source_mnt="$_source"
fi
if ! mount_nullfs -o ro "$_source_mnt" "$_mountpoint" ; then
_error "Failed to mount source inside the pot"
return 1
fi
}
pot-copy-in()
{
local _pname _source _destination _to_be_umount _rc _force _proot _cp_opt _create_dirs
OPTIND=1
_pname=
_destination=
_force=
_cp_opt="-a"
_create_dirs=
while getopts "hvs:d:p:Fc" _o ; do
case "$_o" in
h)
copy-in-help
return 0
;;
F)
_force="YES"
;;
v)
_POT_VERBOSITY=$(( _POT_VERBOSITY + 1))
_cp_opt="-va"
;;
s)
_source="$OPTARG"
;;
p)
_pname="$OPTARG"
;;
d)
_destination="$OPTARG"
;;
c)
_create_dirs="YES"
;;
*)
copy-in-help
return 1
;;
esac
done
if [ -z "$_pname" ]; then
_error "A pot name is mandatory"
copy-in-help
return 1
fi
if [ -z "$_source" ]; then
_error "A source is mandatory"
copy-in-help
return 1
fi
if [ -z "$_destination" ]; then
_error "A destination is mandatory"
copy-in-help
return 1
fi
if ! _is_absolute_path "$_destination" ; then
_error "The destination has to be an absolute pathname"
return 1
fi
if ! _is_pot "$_pname" ; then
_error "pot $_pname is not valid"
copy-in-help
return 1
fi
if ! _is_uid0 ; then
return 1
fi
if ! _source_validation "$_source" ; then
copy-in-help
return 1
fi
if _is_pot_running "$_pname" ; then
if [ "$_force" != "YES" ]; then
_error "Copying files on a running pot is discouraged, it can partially expose the host file system to the jail"
_info "Using the -F flag, the operation can be executed anyway, but we disagree"
return 1
else
_debug "Copying files on a running pot allowed, because of the -F flag"
fi
else
_pot_mount "$_pname"
_to_be_umount=1
fi
_proot=${POT_FS_ROOT}/jails/$_pname/m
if [ "$_create_dirs" = "YES" ]; then
if _is_pot_running "$_pname" ; then
if jexec "$_pname" /bin/mkdir -p "$(dirname "$_destination")" ; then
_debug "Destination path $_destination created in the pot $_pname"
else
_error "Destination path $_destination NOT created because of an error"
if [ "$_to_be_umount" = "1" ]; then
_pot_umount "$_pname"
fi
return 1
fi
else
if jail -c path="$_proot" command=/bin/mkdir -p "$(dirname "$_destination")" ; then
_debug "Destination path $_destination created in the pot $_pname"
else
_error "Destination path $_destination NOT created because of an error"
if [ "$_to_be_umount" = "1" ]; then
_pot_umount "$_pname"
fi
return 1
fi
fi
fi
if ! _source_mountpoint="$( _make_temp_source "$_proot" )" ; then
_error "Failed to build a temporary folder in the pot /tmp"
if [ "$_to_be_umount" = "1" ]; then
_pot_umount "$_pname"
fi
return 1
fi
if ! _mount_source_into_potroot "$_source" "$_source_mountpoint" ; then
if [ "$_to_be_umount" = "1" ]; then
_pot_umount "$_pname"
fi
return 1
fi
if [ -f "$_source" ]; then
_cp_source="/tmp/$( basename "$_source_mountpoint" )/$( basename "$_source" )"
else
_cp_source="/tmp/$( basename "$_source_mountpoint" )"
fi
if _is_pot_running "$_pname" ; then
if jexec "$_pname" /bin/cp "$_cp_opt" "$_cp_source" "$_destination" ; then
_debug "Source $_source copied in the pot $_pname"
_rc=0
else
_error "Source $_source NOT copied because of an error"
_rc=1
fi
else
if jail -c path="$_proot" command=/bin/cp "$_cp_opt" "$_cp_source" "$_destination" ; then
_debug "Source $_source copied in the pot $_pname"
_rc=0
else
_error "Source $_source NOT copied because of an error"
_rc=1
fi
fi
if ! umount -f "$_source_mountpoint" ; then
_error "Failed to unmount the source tmp folder from the pot"
_rc=1
fi
if [ "$_to_be_umount" = "1" ]; then
_pot_umount "$_pname"
else
rmdir "$_source_mountpoint"
fi
return $_rc
}
================================================
FILE: share/pot/copy-out.sh
================================================
#!/bin/sh
# shellcheck disable=SC3033,SC3040,SC3043
:
copy-out-help()
{
cat <<-"EOH"
pot copy-out [-hv] -p pot -s source -d dest
-h print this help
-v verbose
-F force copy operation for running jails
(warning: can expose parts of the host file system)
-p pot : the working pot
-s source : the file or directory inside the pot
-d dest : the location (directory) on the host to copy-out to
EOH
}
# $1 source
_destination_validation()
{
local _destination
_destination="$1"
if [ -r "$_destination" ] && [ -d "$_destination" ] && [ -x "$_destination" ]; then
return 0 # true
else
_error "$_destination not valid"
fi
}
_make_temp_destination()
{
local _proot
_proot="$1"
mktemp -d "$_proot/tmp/copy-out${POT_MKTEMP_SUFFIX}"
}
_mount_destination_into_potroot()
{
local _destination _mountpoint
_destination="$1"
_mountpoint="$2"
if ! mount_nullfs "$_destination" "$_mountpoint" ; then
_error "Failed to mount destination inside the pot"
return 1
fi
}
pot-copy-out()
{
local _pname _source _destination _to_be_umount _rc _force _proot _cp_opt _destination_mountpoint
OPTIND=1
_pname=
_destination=
_force=
_cp_opt="-a"
while getopts "hvs:d:p:F" _o ; do
case "$_o" in
h)
copy-out-help
return 0
;;
F)
_force="YES"
;;
v)
_POT_VERBOSITY=$(( _POT_VERBOSITY + 1))
_cp_opt="-va"
;;
s)
_source="$OPTARG"
;;
p)
_pname="$OPTARG"
;;
d)
_destination="$OPTARG"
;;
*)
copy-out-help
return 1
;;
esac
done
if [ -z "$_pname" ]; then
_error "A pot name is mandatory"
copy-out-help
return 1
fi
if [ -z "$_source" ]; then
_error "A source is mandatory"
copy-out-help
return 1
fi
if [ -z "$_destination" ]; then
_error "A destination is mandatory"
copy-out-help
return 1
fi
if ! _is_absolute_path "$_source" ; then
_error "The source has to be an absolute pathname"
return 1
fi
if ! _is_pot "$_pname" ; then
_error "pot $_pname is not valid"
copy-out-help
return 1
fi
if ! _is_uid0 ; then
return 1
fi
if ! _destination_validation "$_destination" ; then
copy-out-help
return 1
fi
if _is_pot_running "$_pname" ; then
if [ "$_force" != "YES" ]; then
_error "Copying files from a running pot is discouraged, it can partially expose the host file system to the jail"
_info "Using the -F flag, the operation can be executed anyway, but we disagree"
return 1
else
_debug "Copying files from a running pot allowed, because of the -F flag"
fi
else
_pot_mount "$_pname"
_to_be_umount=1
fi
_proot=${POT_FS_ROOT}/jails/$_pname/m
if ! _destination_mountpoint="$( _make_temp_destination "$_proot" )" ; then
_error "Failed to build a temporary folder in the pot /tmp"
if [ "$_to_be_umount" = "1" ]; then
_pot_umount "$_pname"
fi
return 1
fi
if ! _mount_destination_into_potroot "$_destination" "$_destination_mountpoint" ; then
if [ "$_to_be_umount" = "1" ]; then
_pot_umount "$_pname"
fi
return 1
fi
_cp_destination="/tmp/$( basename "$_destination_mountpoint" )"
if _is_pot_running "$_pname" ; then
if jexec "$_pname" /bin/cp "$_cp_opt" "$_source" "$_cp_destination" ; then
_debug "Source $_source copied from the pot $_pname"
_rc=0
else
_error "Source $_source NOT copied because of an error"
_rc=1
fi
else
if jail -c path="$_proot" command=/bin/cp "$_cp_opt" "$_source" "$_cp_destination" ; then
_debug "Source $_source copied from the pot $_pname"
_rc=0
else
_error "Source $_source NOT copied because of an error"
_rc=1
fi
fi
if ! umount -f "$_destination_mountpoint" ; then
_error "Failed to unmount the source tmp folder from the pot"
_rc=1
fi
if [ "$_to_be_umount" = "1" ]; then
_pot_umount "$_pname"
else
rmdir "$_destination_mountpoint"
fi
return $_rc
}
================================================
FILE: share/pot/create-base.sh
================================================
#!/bin/sh
# shellcheck disable=SC3033,SC3040,SC3043
:
# supported releases are defined in common.sh
create-base-help()
{
cat <<-EOH
pot create-base [-h] [-r RELEASE] [-b basename]
-h print this help
-v verbose
-r RELEASE : supported release are: $( _get_valid_releases )
$( _get_valid_releases | xargs -n1 echo " +" | sort)
-b basename : optional, (default: the release)
EOH
}
# $1 base name
_cb_zfs()
{
local _bname _dset _mnt
_bname=$1
_dset="${POT_ZFS_ROOT}/bases/${_bname}"
_mnt="${POT_FS_ROOT}/bases/${_bname}"
_info "Create the zfs datasets for base release $_dset"
if ! _zfs_exist "${_dset}" "${_mnt}" ; then
if ! zfs create "$_dset" ; then
return 1
fi
fi
if ! _zfs_exist "${_dset}/usr.local" "${_mnt}/usr/local" ; then
if ! zfs create -o mountpoint="${_mnt}/usr/local" "$_dset/usr.local" ; then
return 1
fi
fi
if ! _zfs_exist "${_dset}/custom" "${_mnt}/opt/custom" ; then
if ! zfs create -o mountpoint="${_mnt}/opt/custom" "$_dset/custom" ; then
return 1
fi
fi
return 0
}
# $1 release
# $2 base name
_cb_tar_dir()
{
local _rel _bname _mnt
if echo "$1" | grep -q "RC" ; then
_rel="$1"
else
_rel="$1"-RELEASE
fi
_bname=$2
_mnt="${POT_FS_ROOT}/bases/${_bname}"
(
set -e
cd "$_mnt"
tar xkf "${POT_CACHE}/${_rel}"_base.txz
# add release information
echo "$_rel" > .osrelease
cp -a root opt/custom/
cp -a etc opt/custom/
cp -a var opt/custom/
mkdir -p opt/custom/usr.local.etc
mkdir -p opt/custom/usr.home
# they could be part of flavor
mkdir -p usr/ports
# remove duplicated dirs
chflags -R noschg var/empty
rm -rf etc/ root/ var/
# create links
ln -s opt/custom/etc etc
ln -s opt/custom/root root
ln -s opt/custom/var var
if [ ! -e home ]; then
ln -s opt/custom/usr.home home
fi
cd usr
ln -s ../opt/custom/usr.home home
cd local
ln -s ../../opt/custom/usr.local.etc etc
mkdir -p var.db.pkg
cd ../../opt/custom/var/db
rm -rf pkg
ln -s ../../../../usr/local/var.db.pkg pkg
)
}
# $1 base name
_cb_base_pot()
{
local _bname _pname _tmp
_bname=$1
_tmp=$(echo "$_bname" | sed 's/\./_/')
_pname="base-$_tmp"
_info "Create the related pot [$_pname]"
if ! _is_pot "$_pname" quiet ; then
pot-cmd create -l 0 -b "$_bname" -p "$_pname" -f fbsd-update
fi
_debug "Taking a snapshot fo $_pname"
_pot_zfs_snap_full "$_pname"
}
pot-create-base()
{
local _rel _bname
OPTIND=1
while getopts "hr:b:v" _o ; do
case "$_o" in
h)
create-base-help
${EXIT} 0
;;
v)
_POT_VERBOSITY=$(( _POT_VERBOSITY + 1))
;;
r)
if ! _is_valid_release "$OPTARG" ; then
_error "$OPTARG is not a supported release"
create-base-help
${EXIT} 1
fi
_rel=$OPTARG
;;
b)
if _is_base "$OPTARG" quiet ; then
_error "$OPTARG is already a base"
${EXIT} 1
fi
_bname="$OPTARG"
;;
*)
create-base-help
${EXIT} 1
;;
esac
done
if [ -z "$_rel" ]; then
_error "option -r is mandatory"
create-base-help
${EXIT} 1
fi
if [ -z "$_bname" ]; then
_bname=$_rel
_info "Automatically use $_rel as base name"
fi
if [ "$_bname" != "$_rel" ] && _is_valid_release "$_bname" ; then
_error "$_bname has the name of another valid release and that's forbidden"
create-base-help
${EXIT} 1
fi
if _is_base "$_bname" quiet ; then
_error "$_bname already exist"
${EXIT} 1
fi
if ! _is_uid0 ; then
${EXIT} 1
fi
if ! _is_init ; then
${EXIT} 1
fi
_info "Create a base with release $_rel"
# fetch binaries
if ! _fetch_freebsd "${_rel}" ; then
_error "fetch of ${_rel} RELEASE failed"
${EXIT} 1
fi
# create zfs dataset
if ! _cb_zfs "${_bname}" ; then
_error "zfs dataset of ${_bname} failed"
${EXIT} 1
fi
# move binaries to the dataset and create linkx
_cb_tar_dir "${_rel}" "${_bname}"
# create jail level 0
_cb_base_pot "${_bname}"
}
================================================
FILE: share/pot/create-fscomp.sh
================================================
#!/bin/sh
# shellcheck disable=SC3033,SC3040,SC3043
:
create-fscomp-help()
{
cat <<-"EOH"
pot create-fscomp [-hv] -f name
-h print this help
-v verbose
-f name : the fs component name (mandatory)
EOH
}
pot-create-fscomp()
{
local _dset
_dset=
OPTIND=1
while getopts "hvf:" _o ; do
case "$_o" in
h)
create-fscomp-help
${EXIT} 0
;;
v)
_POT_VERBOSITY=$(( _POT_VERBOSITY + 1))
;;
f)
_dset="${POT_ZFS_ROOT}/fscomp/$OPTARG"
;;
?)
create-fscomp-help
${EXIT} 1
esac
done
if [ -z "$_dset" ]; then
_error "fs component name is missing"
create-fscomp-help
${EXIT} 1
fi
if ! _is_init ; then
${EXIT} 1
fi
if ! _zfs_dataset_valid "$_dset" ; then
if ! _is_uid0 ; then
${EXIT} 1
fi
if ! zfs create "$_dset" ; then
_error "fs component $_dset creation failed"
${EXIT} 1
fi
else
_info "fs component $_dset already exists"
fi
return 0
}
================================================
FILE: share/pot/create-private-bridge.sh
================================================
#!/bin/sh
# shellcheck disable=SC3033,SC3040,SC3043
:
create-private-bridge-help()
{
cat <<-"EOH"
pot create-private-bridge [-hv] [-B name] [-S size]
-h print this help
-v verbose
-B bridge name
-S bridge size (number of host expected)
EOH
}
# $1 bridge-name
# $2 bridge-size
create-bridge()
{
local _bconf _bname _bsize
_bname=$1
_bsize=$2
_bconf="${POT_FS_ROOT}/bridges/$_bname"
if potnet new-net -s "$_bsize" > "$_bconf" ; then
echo "name=$_bname" >> "$_bconf"
else
rm -f "$_bconf"
_error "Not able to get a valid network with size $_bsize"
${EXIT} 1
fi
}
pot-create-private-bridge()
{
local _bname _host_amount
OPTIND=1
while getopts "hvB:S:" _o ; do
case "$_o" in
h)
create-private-bridge-help
${EXIT} 0
;;
v)
_POT_VERBOSITY=$(( _POT_VERBOSITY + 1))
;;
B)
_bname="$OPTARG"
;;
S)
_host_amount="$OPTARG"
;;
?)
create-private-bridge-help
${EXIT} 1
esac
done
if [ -z "$_bname" ]; then
_error "A bridge name is mandatory (-B option)"
${EXIT} 1
fi
if [ -z "$_host_amount" ]; then
_error "The amount of host is mandatory (-S option)"
${EXIT} 1
fi
if ! _is_potnet_available ; then
_error "potnet is not available! It's needed - cannot proceed"
${EXIT} 1
fi
if _is_bridge "$_bname" quiet ; then
_error "A bridge with name $_bname already exists"
${EXIT} 1
fi
if ! _is_uid0 ; then
${EXIT} 1
fi
mkdir -p "${POT_FS_ROOT}/bridges"
create-bridge "$_bname" "$_host_amount"
}
================================================
FILE: share/pot/create.sh
================================================
#!/bin/sh
# shellcheck disable=SC3033,SC3040,SC3043
:
trap _cj_undo_create TERM INT
_set_pipefail
create-help()
{
cat <<-"EOH"
pot create [-hv] -p potname [-N network-type] [-i ipaddr]
[-l lvl] [-f flavour] [-b base|-P basepot]
[-d dns] [-t type]
-h print this help
-v verbose
-k keep the pot, if create fails
-p potname : the pot name (mandatory)
-l lvl : pot level (only for type multi)
-b base : the base pot
-P pot : the pot to be used as reference
-d dns : pot dns resolver configuration, one of
inherit* - inherit from jailhost (*default)
pot - the pot configured in POT_DNS_NAME
custom:<file> - copy <file> into pot configuration
off - leave resolver config unaltered
-f flavour : flavour to be used
-t type: pot file system layout, one of
single - the pot is based on a unique ZFS dataset
multi* - the pot is composed by a classical
collection of 3 ZFS datasets (*default)
-N network-type: pot network layout, one of
inherit* - inherit the host network stack (*default)
alias - configure a static ip alias directly on
the host's NIC
public-bridge - use the common internal public bridge
private-bridge - use an internal private bridge (with -B)
-i ipaddr : IP address selection, one of
auto* - automatically assign address (*default),
only works with (public|private)-bridge
ipaddr - mandatory with alias,
also works with (public|private)-bridge
-B bridge-name : the name of the private bridge to be used
-S network-stack : the network stack (ipv4, ipv6 or dual)
EOH
}
_cj_undo_create()
{
_POT_VERBOSITY=0
if [ -z "$_cleanup_pname" ]; then
${EXIT} 1
fi
pot-cmd stop "$_cleanup_pname"
if [ "$_cleanup_keep" != "YES" ]; then
pot-cmd destroy -Fp "$_cleanup_pname" -q
fi
unset _cleanup_pname
unset _cleanup_keep
${EXIT} 1
}
# $1 pot name
# $2 pot-base name
_c_zfs_single()
{
local _pname _base _potbase _jdset _snap _dset
_pname=$1
_potbase=$2
_pdset=${POT_ZFS_ROOT}/jails/$_pname
_pdir=${POT_FS_ROOT}/jails/$_pname
# Create the main jail zfs dataset
if ! _zfs_dataset_valid "$_pdset" ; then
if ! zfs create "$_pdset" ; then
_error "create: failed to create $_pdset dataset"
_cj_undo_create
return 1
fi
else
_info "$_pdset exists already"
fi
if [ -z "$_potbase" ]; then
# create an empty dataset
if ! zfs create "$_pdset/m" ; then
_error "create: failed to create $_pdset/m dataset"
_cj_undo_create
return 1
fi
# create the minimum needed tree
mkdir -p "$_pdir/m/tmp"
chmod 1777 "$_pdir/m/tmp"
mkdir -p "$_pdir/m/dev"
else
# send/receive the last snapshot of _potbase
_dset=${POT_ZFS_ROOT}/jails/$_potbase/m
_snap=$(_zfs_last_snap "$_dset")
if [ -n "$_snap" ]; then
_debug "Clone zfs snapshot $_dset@$_snap"
# shellcheck disable=SC2046
if ! zfs send "$_dset@$_snap" | zfs receive \
$(_get_zfs_receive_extra_args) "$_pdset/m" ; then
_error "create: zfs send/receive failed"
_cj_undo_create
return 1 # false
fi
else
# TODO - autofix
_error "no snapshot found for $_dset/m"
_cj_undo_create
return 1 # false
fi
fi
return 0
}
# $1 pot name
# $2 level
# $3 base name
# $4 pot-base name
_c_zfs_multi()
{
local _pname _base _potbase _jdset _snap _dset
_pname=$1
_lvl=$2
_base=$3
_potbase=$4
_pdset="${POT_ZFS_ROOT}/jails/$_pname"
_pdir="${POT_FS_ROOT}/jails/$_pname"
# Create the main jail zfs dataset
if ! _zfs_dataset_valid "$_pdset" ; then
if ! zfs create "$_pdset" ; then
_error "create: failed to create $_pdset dataset"
_cj_undo_create
return 1
fi
else
_info "$_pdset exists already"
fi
# Create the root mountpoint
_create_pot_mountpoint "$_pdir/m"
# lvl 0 images mount directly usr.local and custom
if [ "$_lvl" = "0" ]; then
return 0
fi
# usr.local
if [ "$_lvl" -eq 1 ]; then
# lvl 1 images send/receive the usr.local dataset
if ! _zfs_dataset_valid "$_pdset/usr.local" ; then
if [ -n "$_potbase" ]; then
_dset=${POT_ZFS_ROOT}/jails/$_potbase
else
_dset=${POT_ZFS_ROOT}/bases/$_base
fi
_snap=$(_zfs_last_snap "$_dset/usr.local")
if [ -n "$_snap" ]; then
_debug "Import zfs snapshot $_dset/usr.local@$_snap"
# shellcheck disable=SC2046
if ! zfs send "$_dset/usr.local@$_snap" | zfs receive \
$(_get_zfs_receive_extra_args) "$_pdset/usr.local" ; then
_error "create: zfs send/receive failed"
_cj_undo_create
return 1 # false
fi
if ! zfs destroy "$_pdset/usr.local@$_snap" ; then
_info "create: not able to destroy the snapshot of usr.local - please, do it manually"
fi
else
# TODO - autofix
_error "no snapshot found for $_dset/usr.local"
return 1 # false
fi
else
_info "$_pdset/usr.local exists already"
fi
fi
# custom dataset
if ! _zfs_dataset_valid "$_pdset/custom" ; then
if [ -n "$_potbase" ]; then
_dset=${POT_ZFS_ROOT}/jails/$_potbase/custom
else
_dset=${POT_ZFS_ROOT}/bases/$_base/custom
fi
_snap=$(_zfs_last_snap "$_dset")
if [ -n "$_snap" ]; then
_debug "Clone zfs snapshot $_dset@$_snap"
# shellcheck disable=SC2046
if ! zfs send "$_dset@$_snap" | zfs receive \
$(_get_zfs_receive_extra_args) "$_pdset/custom" ; then
_error "create: zfs send/receive failed"
_cj_undo_create
return 1 # false
fi
if ! zfs destroy "$_pdset/custom@$_snap" ; then
_info "create: not able to destroy the snapshot of custom - please, do it manually"
fi
else
# TODO - autofix
_error "no snapshot found for $_dset"
return 1 # false
fi
else
_info "$_pdset/custom exists already"
fi
return 0 # true
}
# $1 pot name
# $2 type
# $3 level
# $4 base name
# $5 pot-base name
_cj_zfs()
{
local _pname _base _type _potbase _jdset _snap _dset
_pname=$1
_type=$2
_lvl=$3
_base=$4
_potbase=$5
case "$_type" in
"multi")
_c_zfs_multi "$_pname" "$_lvl" "$_base" "$_potbase"
;;
"single")
_c_zfs_single "$_pname" "$_potbase"
;;
esac
}
# $1 pot name
# $2 base name
# $3 network type
# $4 ip
# $5 level
# $6 dns
# $7 type
# $8 private bridge (if network type is private_bridge)
# $9 pot-base name
# $10 network-stack
_cj_conf()
{
local _pname _base _ip _network_type _lvl _jdir _bdir _potbase _dns _type _pblvl _pbpb
local _jdset _bdset _pbdset _baseos _bridge_name _stack
_pname=$1
_base=$2
_network_type=$3
_ip=$4
_lvl=$5
_dns=$6
_type=$7
_bridge_name=$8
_potbase=$9
_stack=${10}
_jdir=${POT_FS_ROOT}/jails/$_pname
_bdir=${POT_FS_ROOT}/bases/$_base
_jdset=${POT_ZFS_ROOT}/jails/$_pname
_bdset=${POT_ZFS_ROOT}/bases/$_base
if [ -n "$_potbase" ]; then
_pblvl=$( _get_conf_var "$_potbase" pot.level )
_pbdset=${POT_ZFS_ROOT}/jails/$_potbase
else
_pblvl=
fi
if [ ! -d "$_jdir/conf" ]; then
mkdir -p "$_jdir/conf"
fi
(
if [ "$_type" = "multi" ]; then
case $_lvl in
0)
echo "$_bdset /"
echo "$_bdset/usr.local /usr/local"
echo "$_bdset/custom /opt/custom"
;;
1)
echo "$_bdset / ro"
echo "$_jdset/usr.local /usr/local zfs-remount"
echo "$_jdset/custom /opt/custom zfs-remount"
;;
2)
echo "$_bdset / ro"
if [ "$_pblvl" -eq 1 ]; then
echo "$_pbdset/usr.local /usr/local ro"
else
_pbpb="$( _get_conf_var "$_potbase" pot.potbase )"
echo "${POT_ZFS_ROOT}/jails/$_pbpb/usr.local /usr/local ro"
fi
echo "$_jdset/custom /opt/custom zfs-remount"
;;
esac
fi
) > "$_jdir/conf/fscomp.conf"
(
if [ "$_type" = "multi" ]; then
_baseos="$( cat "$_bdir/.osrelease" )"
else
_baseos="${_base}"
fi
echo "pot.level=${_lvl}"
echo "pot.type=${_type}"
echo "pot.base=${_base}"
echo "pot.potbase=${_potbase}"
if [ "$_dns" = "${_dns##custom:}" ]; then
echo "pot.dns=${_dns}"
else
echo "pot.dns=custom"
fi
echo "pot.cmd=sh /etc/rc"
echo "host.hostname=\"$( _get_usable_hostname "${_pname}" )\""
if echo "$_baseos" | grep -q "RC" ; then
echo "osrelease=\"${_baseos}\""
elif echo "$_baseos" | grep -q "RELEASE" ; then
echo "osrelease=\"${_baseos}\""
else
echo "osrelease=\"${_baseos}-RELEASE\""
fi
# pot attributes
echo "pot.attr.no-rc-script=NO"
echo "pot.attr.persistent=YES"
echo "pot.attr.start-at-boot=NO"
echo "pot.attr.prunable=NO"
echo "pot.attr.no-tmpfs=NO"
# jail attributes
for _attr in ${_POT_JAIL_RW_ATTRIBUTES} ; do
if [ -z "$(_get_conf_var "$_pname" "pot.attr.${_attr}")" ]; then
# shellcheck disable=SC1083,SC2086
eval _value=\"\${_POT_DEFAULT_${_attr}_D}\"
# shellcheck disable=SC2154
echo "pot.attr.${_attr}=${_value}"
fi
done
echo "pot.stack=$_stack"
echo "network_type=$_network_type"
case $_network_type in
"inherit")
echo "vnet=false"
;;
"alias")
echo "vnet=false"
echo "ip=${_ip}"
;;
"public-bridge")
echo "vnet=true"
echo "ip=${_ip}"
;;
"private-bridge")
echo "vnet=true"
echo "ip=${_ip}"
echo "bridge=${_bridge_name}"
;;
esac
if [ "${_dns}" = "pot" ]; then
echo "pot.depend=${POT_DNS_NAME}"
fi
) > "$_jdir/conf/pot.conf"
if [ "$_dns" != "${_dns##custom:}" ]; then
cp "${_dns##custom:}" "$_jdir/conf/resolv.conf"
fi
if [ "$_lvl" -eq 2 ]; then
if [ "$_pblvl" -eq 1 ]; then
# CHANGE the potbase usr.local to be not zfs-remount
# Add an info here would be nice
if [ -w "${POT_FS_ROOT}/jails/$_potbase/conf/fscomp.conf" ]; then
_info "${POT_FS_ROOT}/jails/$_potbase/conf/fscomp.conf fix (${POT_FS_ROOT}/jails/$_potbase/m/usr/local zfs-remount)"
# shellcheck disable=SC2086
${SED} -i '' s%${POT_FS_ROOT}/jails/$_potbase/m/usr/local\ zfs-remount%${POT_FS_ROOT}/jails/$_potbase/m/usr/local% ${POT_FS_ROOT}/jails/$_potbase/conf/fscomp.conf
else
_info "$_potbase fscomp.conf has not fscomp.conf"
fi
fi
fi
if [ "$_type" = "multi" ]; then
_cj_internal_conf "$_pname" "$_type" "$_lvl" "$_ip"
fi
}
# $1 pot name
# $2 type
# $3 level
# $4 ip
_cj_internal_conf()
{
local _pname _type _lvl _ip _jdir
_pname=$1
_type=$2
_lvl=$3
_ip=$4
_jdir=${POT_FS_ROOT}/jails/$_pname
if [ "$_type" = "multi" ]; then
_etcdir="${POT_FS_ROOT}/jails/$_pname/custom/etc"
else
_etcdir="${POT_FS_ROOT}/jails/$_pname/m/etc"
fi
# disable some cron jobs, not relevant in a jail
if [ "$_type" = "single" ] || [ "$_lvl" -ne 0 ]; then
${SED} -i '' 's/^.*save-entropy$/# &/g' "${_etcdir}/crontab"
${SED} -i '' 's/^.*adjkerntz.*$/# &/g' "${_etcdir}/crontab"
fi
# TODO: to be verified
# add remote syslogd capability, if not inherit
# if [ -n "$_ip" ]; then
# # configure syslog in the pot
# ${SED} -i '' 's%^[^#].*/var/log.*$%# &%g' "${_etcdir}/syslog.conf"
# echo "*.* @${POT_GATEWAY}:514" > "${_etcdir}/syslog.d/pot.conf"
# if [ ! -r "${_etcdir}/rc.conf" ]; then
# touch "${_etcdir}/rc.conf"
# fi
# sysrc -f "${_etcdir}/rc.conf" "syslogd_flags=-vv -s -b $_ip" > /dev/null
# # configure syslogd in the host
# (
# echo +"$_ip"
# echo '*.* '"/var/log/pot/${_pname}.log"
# ) > /usr/local/etc/syslog.d/"${_pname}".conf
# touch /var/log/pot/"${_pname}".log
# (
# echo "# log rotation for pot ${_pname}"
# echo "/var/log/pot/${_pname}.log 644 7 * @T00 CX"
# ) > /usr/local/etc/newsyslog.conf.d/"${_pname}".conf
# service syslogd reload
# fi
}
# $1 pot name
# $2 freebsd version
_cj_single_install()
{
local _pname _base _proot _rel
_pname=$1
_base=$2
_proot=${POT_FS_ROOT}/jails/$_pname/m
_info "Fetching FreeBSD $_base"
if ! _fetch_freebsd "$_base" ; then
_error "FreeBSD $_base fetch failed - try to continue"
_cj_undo_create
return 1 # false
fi
if echo "$_base" | grep -q "RC" ; then
_rel="$_base"
else
_rel="$_base"-RELEASE
fi
if [ ! -r "${POT_CACHE}/${_rel}_base.txz" ]; then
_error "FreeBSD base tarball ${POT_CACHE}/${_rel}_base.txz is missing"
_cj_undo_create
return 1 # falase
fi
(
set -e
cd "$_proot"
_info "Extract the tarball"
tar xkf "${POT_CACHE}/${_rel}_base.txz"
if [ ! -d usr/home ]; then
mkdir -p usr/home
fi
if [ ! -e home ]; then
ln -s usr/home home
fi
)
return 0
}
pot-create()
{
local _pname _ipaddr _lvl _base _flv _potbase _dns _type _new_lvl _network_type _private_bridge _network_stack
OPTIND=1
_type="multi"
_network_type="inherit"
_pname=
_base=
_ipaddr=
_lvl=1
_new_lvl=
_flv=
_potbase=
_dns=inherit
_private_bridge=
_network_stack="$( _get_network_stack )"
_cleanup_keep="NO"
while getopts "hvp:t:N:i:l:b:f:P:d:B:S:k" _o ; do
case "$_o" in
h)
create-help
${EXIT} 0
;;
v)
_POT_VERBOSITY=$(( _POT_VERBOSITY + 1))
;;
k)
_cleanup_keep="YES"
;;
p)
if ! _is_valid_potname "$OPTARG" ; then
_error "$OPTARG is not a valid name for a pot ('.' is the only character not allowed)"
${EXIT} 1
fi
_pname="$OPTARG"
;;
t)
if [ "$OPTARG" = "multi" ] || [ "$OPTARG" = "single" ]; then
_type="$OPTARG"
else
_error "Type $OPTARG not supported"
create-help
${EXIT} 1
fi
;;
N)
# shellcheck disable=SC2086
if ! _is_in_list "$OPTARG" $_POT_NETWORK_TYPES ; then
_error "Network type $OPTARG not recognized"
create-help
${EXIT} 1
fi
_network_type="$OPTARG"
;;
B)
_private_bridge="$OPTARG"
;;
S)
if ! _is_in_list "$OPTARG" "ipv4" "ipv6" "dual" ; then
_error "Network stack $OPTARG not valid"
create-help
${EXIT} 1
fi
_network_stack="$OPTARG"
;;
i)
if [ -z "$_ipaddr" ]; then
_ipaddr="$OPTARG"
else
_ipaddr="$_ipaddr $OPTARG"
fi
;;
l)
_lvl="$OPTARG"
_new_lvl="$OPTARG"
;;
b)
_base=$OPTARG
;;
P)
_potbase=$OPTARG
;;
d)
case $OPTARG in
"inherit"|"pot"|"off")
_dns=$OPTARG
;;
custom:*)
if [ -r "${OPTARG##custom:}" ]; then
_dns=$OPTARG
else
_error "The file ${OPTARG##custom:} is not valid or readable"
${EXIT} 1
fi
;;
*)
_error "'${OPTARG}' is not a valid dns option"
create-help
${EXIT} 1
esac
;;
f)
if _is_flavour "$OPTARG" ; then
if [ -z "$_flv" ]; then
_flv=$OPTARG
else
_flv="$_flv $OPTARG"
fi
else
_error "Flavour $OPTARG not found"
_debug "Looking in the flavour dir ${_POT_FLAVOUR_DIR}"
${EXIT} 1
fi
;;
*)
create-help
${EXIT} 1
;;
esac
done
# check options consitency
if [ "$_type" = "single" ]; then
if [ -n "$_new_lvl" ] && [ "$_new_lvl" != "0" ]; then
_error "single pot level can only be zero (omit -l option)"
create-help
${EXIT} 1
fi
_lvl=0
if [ -n "$_potbase" ]; then
if ! _is_pot "$_potbase" quiet ; then
_error "pot $_potbase not found"
create-help
${EXIT} 1
fi
if [ "$( _get_pot_type "$_potbase" )" != "single" ]; then
_error "pot $_potbase has the wrong type, it has to be of type single"
create-help
${EXIT} 1
fi
if [ -z "$_base" ]; then
_base="$( _get_pot_base "$_potbase" )"
elif [ "$( _get_pot_base "$_potbase" )" != "$_base" ]; then
_error "-b $_base and -P $_potbase are not compatible"
create-help
${EXIT} 1
fi
else
if [ -z "$_base" ]; then
_error "at least one of -b and -P has to be used"
create-help
${EXIT} 1
fi
if ! _is_valid_release "$_base" ; then
_error "$_base is not a valid release"
create-help
${EXIT} 1
fi
fi
else
case $_lvl in
0)
if [ -z "$_base" ]; then
_error "level $_lvl needs option -b"
create-help
${EXIT} 1
fi
if [ -n "$_potbase" ]; then
_error "-P option is not allowed with level $_lvl"
create-help
${EXIT} 1
fi
if ! _is_base "$_base" quiet ; then
_error "$_base is not a valid base"
create-help
${EXIT} 1
fi
;;
1)
if [ -z "$_base" ] && [ -z "$_potbase" ]; then
_error "at least one of -b and -P has to be used"
create-help
${EXIT} 1
fi
if [ -n "$_base" ] && [ -n "$_potbase" ]; then
if [ "$( _get_pot_base "$_potbase" )" != "$_base" ]; then
_error "-b $_base and -P $_potbase are not compatible"
create-help
${EXIT} 1
fi
# TODO: an info or debug message che be showned
fi
if [ -n "$_potbase" ]; then
if ! _is_pot "$_potbase" ; then
_error "-P $_potbase : is not a pot"
create-help
${EXIT} 1
fi
if [ "$( _get_conf_var "$_potbase" pot.level )" != "1" ]; then
_error "-P $_potbase : it has to be of level 1"
create-help
${EXIT} 1
fi
fi
if [ -z "$_base" ]; then
_base=$( _get_pot_base "$_potbase" )
if [ -z "$_base" ]; then
_error "-P $_potbase has no base??"
${EXIT} 1
fi
_debug "-P $_potbase induced -b $_base"
fi
if ! _is_base "$_base" quiet ; then
_error "$_base is not a valid base"
create-help
${EXIT} 1
fi
;;
2)
if [ -z "$_potbase" ]; then
_error "level $_lvl pots need another pot as reference"
create-help
${EXIT} 1
fi
if [ "$( _get_conf_var "$_potbase" pot.level )" -lt 1 ]; then
_error "-P $_potbase : it has to be at least of level 1"
create-help
${EXIT} 1
fi
if ! _is_pot "$_potbase" ; then
_error "-P $_potbase : is not a pot"
create-help
${EXIT} 1
fi
if [ -n "$_base" ]; then
if ! _is_base "$_base" quiet ; then
_error "$_base is not a valid base"
create-help
${EXIT} 1
fi
if [ "$( _get_pot_base "$_potbase" )" != "$_base" ]; then
_error "-b $_base and -P $_potbase are not compatible"
${EXIT} 1
fi
else
_base=$( _get_pot_base "$_potbase" )
if [ -z "$_base" ]; then
_error "-P $_potbase has no base??"
${EXIT} 1
fi
if ! _is_base "$_base" quiet ; then
_error "$_base (induced by the pot $_potbase) is not a valid base"
create-help
${EXIT} 1
fi
fi
;;
*)
_error "level $_lvl is not supported"
${EXIT} 1
;;
esac
fi
if [ -z "$_pname" ]; then
_error "pot name is missing"
create-help
${EXIT} 1
fi
if _is_pot "$_pname" quiet ; then
_error "pot $_pname already exists"
${EXIT} 1
fi
if ! _is_uid0 ; then
${EXIT} 1
fi
if ! _ipaddr="$( _validate_network_param "$_network_type" "$_ipaddr" "$_private_bridge" "$_network_stack" )" ; then
echo "$_ipaddr"
${EXIT} 1
fi
if [ "$_dns" = "pot" ]; then
if ! _is_vnet_available ; then
_error "This kernel doesn't support VIMAGE! No vnet possible (needed by the dns)"
${EXIT} 1
fi
if ! _is_pot "${POT_DNS_NAME}" quiet ; then
_error "dns pot not found ($POT_DNS_NAME) - please fix it"
${EXIT} 1
fi
fi
_info "Creating a new pot"
_info "pot name : $_pname"
_info "type : $_type"
_info "base : $_base"
_info "pot_base : $_potbase"
_info "level : $_lvl"
_info "network-type : $_network_type"
_info "network-stack: $_network_stack"
_info "ip : $_ipaddr"
_info "bridge : $_private_bridge"
_info "dns : $_dns"
_info "flavours : $_flv"
export _cleanup_pname="$_pname" # for the cleanup function
export _cleanup_keep
if ! _cj_zfs "$_pname" "$_type" "$_lvl" "$_base" "$_potbase" ; then
${EXIT} 1
fi
if ! _cj_conf "$_pname" "$_base" "$_network_type" "$_ipaddr" "$_lvl" "$_dns" "$_type" "$_private_bridge" "$_potbase" "$_network_stack" ; then
${EXIT} 1
fi
if [ "$_type" = "single" ]; then
if [ -z "$_potbase" ]; then
_cj_single_install "$_pname" "$_base"
fi
_cj_internal_conf "$_pname" "$_type" "0" "$_ipaddr"
fi
if [ -n "$_flv" ]; then
for _f in $_flv ; do
if ! _exec_flv "$_pname" "$_f" ; then
_cj_undo_create
${EXIT} 1
fi
done
fi
unset _cleanup_pname
unset _cleanup_keep
}
================================================
FILE: share/pot/de-init.sh
================================================
#!/bin/sh
# shellcheck disable=SC3033,SC3040,SC3043
:
de-init-help()
{
cat <<-"EOH"
pot de-init [-hmvf] [-p pf_file]
-f force : stop all running pots
-p pf_file : remove anchors to this file (empty to skip),
defaults to result of `sysrc -n pf_rules`
-h print this help
-m minimal modifications (alias for `-p ''`)
WARNING: Still destroys POT_ZFS_ROOT
-v verbose
EOH
}
pot-de-init()
{
local _pots _p _force _zopt _pf_file
_force=
_zopt=
_pf_file="$(sysrc -n pf_rules)"
OPTIND=1
while getopts "fhmvp:" _o ; do
case "$_o" in
f)
_force="force"
;;
h)
de-init-help
${EXIT} 0
;;
m)
_pf_file=""
;;
p)
_pf_file="$OPTARG"
;;
v)
_POT_VERBOSITY=$(( _POT_VERBOSITY + 1))
_zopt="-v"
;;
?)
de-init-help
${EXIT} 1
;;
esac
done
_pots=_get_pot_list
if ! _is_uid0 ; then
${EXIT} 1
fi
for _p in $_pots ; do
if _is_pot_running "$_p" ; then
if [ -n "$_force" ]; then
_debug "Stop the pot $_p"
pot-cmd stop "$_p"
else
_error "At least on pot is still running. Use -f to force the stop of all pots"
${EXIT} 1
fi
fi
done
# Remove pot dataset
if ! _zfs_dataset_valid "${POT_ZFS_ROOT}" ; then
_info "no root dataset found ($POT_ZFS_ROOT)"
else
_info "Deinstall pot ($POT_ZFS_ROOT)"
zfs destroy -r $_zopt "${POT_ZFS_ROOT}"
fi
echo "zfs datasets have been removed"
# Remove pf entries if needed
if [ -n "$_pf_file" ]; then
sed -i '' '/^nat-anchor pot-nat$/d' "$_pf_file"
sed -i '' '/^rdr-anchor "pot-rdr\/\*"$/d' "$_pf_file"
echo "pf configuration file should be clean"
echo " - please check $_pf_file and reload it"
fi
# Final message
echo "check your rc.conf for potential leftovers variable like:"
echo ' syslogd_flags'
echo ' pot_enable'
echo "Please, consider to write a feedback email to pizzamig at FreeBSD dot org"
echo "It gives us the opportunity to learn and improve"
}
================================================
FILE: share/pot/destroy.sh
================================================
#!/bin/sh
# shellcheck disable=SC3033,SC3040,SC3043
:
destroy-help()
{
cat <<-"EOH"
pot destroy [-hvFr] [-p potname|-b basename|-f fscomp|-B bridge]
-h print this help
-v verbose
-q quiet
-F force the stop and destroy
-p potname : the pot name (mandatory)
-b basename : the base name (mandatory)
-f fscomp : the fscomp name (mandatory)
-B bridge-name : the name of the bridge to be deleted (mandatory)
-r : destroy recursively all pots based on this base/pot
EOH
}
# $1 zfs dataset
_zfs_dataset_destroy()
{
local _dset _zopt
_dset=$1
_zopt=
if _is_verbose ; then
_zopt="-v"
fi
zfs destroy -f -r $_zopt "$_dset"
return $?
}
# $1 pot name
# $2 force parameter
_pot_zfs_destroy()
{
local _pname _zopt _jdset _force
_pname=$1
_force=$2
_jdset=${POT_ZFS_ROOT}/jails/$_pname
if ! _zfs_dataset_valid "$_jdset" ; then
## if a directory is found, just remove if
if [ -d "${POT_FS_ROOT}/jails/$_pname" ]; then
_debug "Dataset of $_pname not found, but removing the directory anyway"
rm -rf "${POT_FS_ROOT}/jails/$_pname"
return 0 # true
fi
_error "$_pname not found"
return 1 # false
fi
if _is_pot_running "$_pname" ; then
if [ "$_force" = "YES" ]; then
pot-cmd stop "$_pname"
else
_error "pot $_pname is running"
${EXIT} 1
fi
fi
if ! _zfs_dataset_destroy "$_jdset" ; then
_error "zfs failed to destroy the dataset $_jdset"
return 1 # false
fi
if [ -d "${POT_FS_ROOT}/jails/$_pname" ]; then
_debug "Removing leftover mountpoint ${POT_FS_ROOT}/jails/$_pname"
rm -rf "${POT_FS_ROOT}/jails/$_pname"
fi
rm -f "/usr/local/etc/syslog.d/${_pname}.conf" "/usr/local/etc/newsyslog.conf.d/${_pname}.conf" "/var/log/pot/${_pname}.log"
return $?
}
# $1 base name
_base_zfs_destroy()
{
local _bname _bdset
_bname=$1
_bdset=${POT_ZFS_ROOT}/bases/$_bname
if ! _zfs_dataset_destroy "$_bdset" ; then
_error "zfs failed to destroy the dataset $_bdset"
return 1 # false
fi
if [ -d "${POT_FS_ROOT}/bases/$_bname" ]; then
_debug "Removing leftover mountpoint ${POT_FS_ROOT}/bases/$_bname"
rm -rf "${POT_FS_ROOT}/bases/$_bname"
fi
return 0
}
# $1 base name
_fscomp_zfs_destroy()
{
local _fname _fdset
_fname=$1
_fdset=${POT_ZFS_ROOT}/fscomp/$_fname
if ! _zfs_dataset_destroy "$_fdset" ; then
_error "zfs failed to destroy the dataset $_fdset"
return 1 # false
fi
if [ -d "${POT_FS_ROOT}/fscomp/$_fname" ]; then
_debug "Removing leftover mountpoint ${POT_FS_ROOT}/fscomp/$_fname"
rm -rf "${POT_FS_ROOT}/fscomp/$_fname"
fi
return 0
}
pot-destroy()
{
local _pname _bname _fname _force _recursive _pots _depPot _bridge_name
_pname=
_bname=
_fname=
_bridge_name=
_force=
_recursive="NO"
OPTIND=1
while getopts "hvrf:p:b:FB:q" _o ; do
case "$_o" in
h)
destroy-help
${EXIT} 0
;;
v)
_POT_VERBOSITY=$(( _POT_VERBOSITY + 1))
;;
q)
_POT_VERBOSITY=0
;;
F)
_force="YES"
;;
r)
_recursive="YES"
;;
p)
_pname=$OPTARG
;;
b)
_bname=$OPTARG
;;
f)
_fname=$OPTARG
;;
B)
_bridge_name=$OPTARG
;;
*)
destroy-help
${EXIT} 1
;;
esac
done
if [ -z "$_pname" ] && [ -z "$_bname" ] && [ -z "$_fname" ] && [ -z "$_bridge_name" ]; then
_error "-b or -p or -f or -B are missing"
destroy-help
${EXIT} 1
fi
if [ -n "$_pname" ]; then
if [ -n "$_bname" ] || [ -n "$_fname" ] || [ -n "$_bridge_name" ] ; then
_error "-b, -p, -f and -B cannot be used at the same time"
destroy-help
${EXIT} 1
fi
fi
if [ -n "$_bname" ]; then
if [ -n "$_fname" ] || [ -n "$_bridge_name" ] ; then
_error "-b, -p, -f and -B cannot be used at the same time"
destroy-help
${EXIT} 1
fi
fi
if [ -n "$_fname" ] && [ -n "$_bridge_name" ] ; then
_error "-b, -p, -f and -B cannot be used at the same time"
destroy-help
${EXIT} 1
fi
if ! _is_uid0 ; then
${EXIT} 1
fi
if [ -n "$_bridge_name" ]; then
if [ "$_force" = "YES" ] || [ "$_recursive" = "YES" ] ; then
_info "Destroy bridge will ignore force and recursive"
fi
if ! _is_bridge "$_bridge_name" ; then
_error "$_bridge_name is not a valid bridge name"
${EXIT} 1
fi
_pots=$( _get_pot_list )
for _p in $_pots ; do
_bridge="$( _get_conf_var "$_p" bridge)"
if [ "$_bridge" = "$_bridge_name" ]; then
_error "the bridge $_bridge_name is still used by the pot $_p - unable to delete"
${EXIT} 1
fi
done
_info "Destroying bridge $_bridge_name"
rm -f "${POT_FS_ROOT}/bridges/$_bridge_name"
${EXIT} $?
fi
if [ -n "$_fname" ]; then
if [ "$_force" = "YES" ] || [ "$_recursive" = "YES" ] ; then
_info "Destroy fscomps will ignore force and recursive"
fi
if ! _zfs_dataset_valid "${POT_ZFS_ROOT}/fscomp/$_fname" ; then
_error "$_fname is not a fscomp"
${EXIT} 1
fi
_info "Destroying fscomp $_fname"
_fscomp_zfs_destroy "$_fname"
${EXIT} $?
fi
if [ -n "$_bname" ]; then
# check the base
if ! _zfs_dataset_valid "${POT_ZFS_ROOT}/bases/$_bname" ; then
_error "$_bname is not a base"
${EXIT} 1
fi
if [ "$_recursive" = "YES" ]; then
for _lvl in 2 1 0 ; do
_pots=$( _get_pot_list )
for _p in $_pots ; do
if [ "$( _get_conf_var "$_p" pot.level )" = "$_lvl" ]; then
if [ "$( _get_conf_var "$_p" pot.base )" = "$_bname" ]; then
_info "Destroying recursively pot $_p based on $_bname"
_pot_zfs_destroy "$_p" $_force
fi
fi
done
done
else
# check if some pot depends on it
_pots=$( _get_pot_list )
_pname="base-$(echo "$_bname" | sed 's/\./_/')"
for _p in $_pots ; do
if [ "$_p" = "$_pname" ]; then
continue
fi
if [ "$( _get_conf_var "$_p" pot.base )" = "$_bname" ]; then
_error "base $_bname is used at least by one pot - use option -r to destroy it recursively"
${EXIT} 1
fi
done
# if present, destroy the lvl 0 pot
_debug "Destroying lvl 0 pot $_pname"
_pot_zfs_destroy "$_pname" "$_force"
fi
_info "Destroying base $_bname"
_base_zfs_destroy "$_bname"
${EXIT} $?
fi
if [ -n "$_pname" ]; then
if ! _is_pot "$_pname" quiet ; then
if _zfs_dataset_valid "${POT_ZFS_ROOT}/jails/$_pname" && [ "$_force" = "YES" ] ; then
# we can destroy forcibly
if ! _pot_zfs_destroy "$_pname" "$_force" ; then
_error "Failed to destroy pot $_pname"
${EXIT} 1
else
_info "Forcibly destroyed pot $_pname"
${EXIT} 0
fi
else
_is_pot "$_pname"
_error "pot $_pname not found or corrupted. Try to use the -F flag"
${EXIT} 1 # false
fi
fi
if [ "$( _get_conf_var "$_pname" pot.level )" = "0" ]; then
# if single we can remove a level 0 pot
if [ "$( _get_conf_var "$_pname" pot.type )" = "single" ]; then
_pots=$( _get_pot_list )
for _p in $_pots ; do
if [ "$( _get_conf_var "$_p" pot.potbase )" = "$_pname" ]; then
if [ "$_recursive" = "YES" ]; then
_debug "Destroying recursively pot $_p based on $_pname"
_pot_zfs_destroy "$_p" $_force
else
_error "$_pname is used at least by another pot ($_p) - use option -r to destroy it recursively"
${EXIT} 1
fi
fi
done
else
_error "The pot $_pname has level 0. Please destroy the related base insted"
${EXIT} 1
fi
fi
if [ "$( _get_conf_var "$_pname" pot.level )" = "1" ]; then
_pots=$( _get_pot_list )
for _p in $_pots ; do
if [ "$( _get_conf_var "$_p" pot.potbase )" = "$_pname" ]; then
if [ "$_recursive" = "YES" ]; then
_debug "Destroying recursively pot $_p based on $_pname"
_pot_zfs_destroy "$_p" $_force
else
_error "$_pname is used at least by one level 2 pot - use option -r to destroy it recursively"
${EXIT} 1
fi
fi
done
fi
if [ "$( _get_conf_var "$_pname" pot.level )" = "2" ] && [ "$_recursive" = "YES" ]; then
_debug "$_pname has level 2. No recursive destroy possible (ignored)"
fi
## dependency detection
_pots=$( _get_pot_list )
for _p in $_pots ; do
_depPot="$( _get_conf_var "$_p" pot.depend )"
if [ -z "$_depPot" ]; then
continue
fi
for _d in $_depPot ; do
if [ "$_d" = "$_pname" ]; then
_info "pot $_p is losing his dependency $_pname"
continue
fi
done
done
_info "Destroying pot $_pname"
if ! _pot_zfs_destroy "$_pname" $_force ; then
_error "$_pname destruction failed"
${EXIT} 1
fi
fi
if [ -f "${POT_TMP:-/tmp}/pot_status_${_pname}" ]; then
rm -f "${POT_TMP:-/tmp}/pot_status_${_pname}"
fi
}
================================================
FILE: share/pot/exec.sh
================================================
#!/bin/sh
# shellcheck disable=SC3033,SC3040,SC3043
:
exec-help()
{
cat <<-"EOH"
pot exec [-hvdt] [-e var=value] [-u username] [-U username]
-p pot COMMAND
-h print this help
-v verbose
-d detach, run in background
-t allocate pty
-e var=value : set environment variable, can be repeated
-u username: The username from the host environment as whom the
command should run
-U username: The username from the pot environment as whom the
command should run
-p pot : the pot image
COMMAND is the command to execute and will be executed in the
username's $HOME
EOH
}
# Actually send signal to process inside pot
# $1 pot name
# $2 detach
# $3 env (encoded with save_params)
# $4 alloc_pty
# $5 user_host
# $6 user_pot
# $7-$n command/args
_exec_cmd()
{
local _pname _detach _env _alloc_pty _user_host _user_pot
local _cmd
_pname=$1
_detach=$2
_env=$3
_alloc_pty=$4
_user_host=$5
_user_pot=$6
shift 6 # $@ contains command/args now
_debug "Exec in $_pname, cmd: $*"
# assemble command
_cmd=
if [ "$_alloc_pty" = "YES" ]; then
_cmd="$_cmd"$(_save_params "script" "-q" "/dev/null")
fi
_cmd="$_cmd"$(_save_params "jexec" "-l")
if [ -n "$_user_host" ]; then
_cmd="$_cmd"$(_save_params "-u" "$_user_host")
elif [ -n "$_user_pot" ]; then
_cmd="$_cmd"$(_save_params "-U" "$_user_pot")
fi
_cmd="$_cmd"$(_save_params "$_pname")
_cmd="$_cmd$_env"$(_save_params "$@")
# execute command
eval "set -- $_cmd"
if [ "$_detach" = "YES" ]; then
nohup "$@" >/dev/null 2>&1 &
else
"$@"
fi
_ret=$?
return "$_ret"
}
pot-exec()
{
local _pname _detach _env _alloc_pty _user_host _user_pot _ret
_pname=
_detach="NO"
_env=$(_save_params "env")
_alloc_pty="NO"
_user_host=
_user_pot=
OPTIND=1
while getopts "hvdtp:e:u:U:" _o ; do
case "$_o" in
h)
exec-help
${EXIT} 0
;;
v)
_POT_VERBOSITY=$(( _POT_VERBOSITY + 1))
;;
d)
_detach="YES"
;;
t)
_alloc_pty="YES"
;;
e)
if [ "$OPTARG" = "${OPTARG#*=}" ]; then
# the argument doesn't have an equal sign
_error "$OPTARG not in a valid form"
_error "VARIABLE=value is accetped"
exec-help
${EXIT} 1
fi
_env="$_env"$(_save_params "$OPTARG")
;;
u)
_user_host="$OPTARG"
;;
U)
_user_pot="$OPTARG"
;;
p)
_pname="$OPTARG"
;;
*)
exec-help
${EXIT} 1
esac
done
shift $((OPTIND-1))
if [ "$#" -eq 0 ]; then
_error "A command is mandatory"
${EXIT} 1
fi
if [ -z "$_pname" ]; then
_error "A pot name is mandatory"
exec-help
${EXIT} 1
fi
if [ -n "$_user_host" ] && [ -n "$_user_pot" ]; then
_error "Parameters -u and -U are mutually exclu
gitextract_cytad9_s/
├── .github/
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug_report.md
│ │ └── feature_request.md
│ └── workflows/
│ ├── ci.yml
│ ├── main.yml
│ └── shellcheck.yml
├── .gitignore
├── .travis.yml
├── CHANGELOG.md
├── Jenkinsfile
├── LICENSE
├── README.md
├── bin/
│ └── pot
├── etc/
│ ├── pot/
│ │ ├── flavours/
│ │ │ ├── dns
│ │ │ ├── dns.sh
│ │ │ ├── fbsd-update.sh
│ │ │ └── slim.sh
│ │ ├── pot.conf.sample
│ │ └── pot.default.conf
│ └── rc.d/
│ ├── pot
│ └── pot_early
├── release.sh
├── share/
│ ├── doc/
│ │ └── pot/
│ │ ├── .gitignore
│ │ ├── Description.md
│ │ ├── Images.md
│ │ ├── Installation.md
│ │ ├── Makefile
│ │ ├── QuickStart.md
│ │ ├── Synopsis.md
│ │ ├── conf.py
│ │ ├── index.md
│ │ └── migration.md
│ ├── pot/
│ │ ├── add-dep.sh
│ │ ├── clone-fscomp.sh
│ │ ├── clone.sh
│ │ ├── common-flv.sh
│ │ ├── common.sh
│ │ ├── config.sh
│ │ ├── copy-in.sh
│ │ ├── copy-out.sh
│ │ ├── create-base.sh
│ │ ├── create-fscomp.sh
│ │ ├── create-private-bridge.sh
│ │ ├── create.sh
│ │ ├── de-init.sh
│ │ ├── destroy.sh
│ │ ├── exec.sh
│ │ ├── export-ports.sh
│ │ ├── export.sh
│ │ ├── get-attribute.sh
│ │ ├── get-rss.sh
│ │ ├── help.sh
│ │ ├── import.sh
│ │ ├── info.sh
│ │ ├── init.sh
│ │ ├── last-run-stats.sh
│ │ ├── list.sh
│ │ ├── mount-in.sh
│ │ ├── mount-out.sh
│ │ ├── network.sh
│ │ ├── prepare.sh
│ │ ├── prune.sh
│ │ ├── ps.sh
│ │ ├── purge-snapshots.sh
│ │ ├── rename.sh
│ │ ├── revert.sh
│ │ ├── set-attribute.sh
│ │ ├── set-cmd.sh
│ │ ├── set-env.sh
│ │ ├── set-hook.sh
│ │ ├── set-hosts.sh
│ │ ├── set-rss.sh
│ │ ├── set-status.sh
│ │ ├── show.sh
│ │ ├── signal.sh
│ │ ├── snapshot.sh
│ │ ├── start.sh
│ │ ├── stop.sh
│ │ ├── term.sh
│ │ ├── top.sh
│ │ ├── update-config.sh
│ │ ├── version.sh
│ │ └── vnet-start.sh
│ └── zsh/
│ └── site-functions/
│ └── _pot
└── tests/
├── CI/
│ ├── resolv.conf-dual
│ ├── resolv.conf-ipv4
│ ├── resolv.conf-ipv6
│ └── run.sh
├── add-dep1.sh
├── clone-fscomp1.sh
├── clone1.sh
├── clone2.sh
├── common-flv1.sh
├── common-stub.sh
├── common-zfs1.sh
├── common-zfs2.sh
├── common1.sh
├── common2.sh
├── common4.sh
├── common5.sh
├── common6.sh
├── common7.sh
├── common8.sh
├── conf-stub.sh
├── config1.sh
├── copy-in1.sh
├── copy-out1.sh
├── create-base1.sh
├── create-fscomp1.sh
├── create-private-bridge1.sh
├── create1.sh
├── create2.sh
├── create3.sh
├── destroy1.sh
├── export-ports1.sh
├── export1.sh
├── get-rss1.sh
├── import1.sh
├── info1.sh
├── info2.sh
├── list1.sh
├── list2.sh
├── monitor.sh
├── mount-in1.sh
├── mount-out1.sh
├── network1.sh
├── pipefail-stub.sh
├── ps1.sh
├── rename1.sh
├── rename2.sh
├── rename3.sh
├── rename4.sh
├── revert1.sh
├── set-attr1.sh
├── set-attr2.sh
├── set-cmd1.sh
├── set-env1.sh
├── set-env2.sh
├── set-hook1.sh
├── set-hosts1.sh
├── set-rss1.sh
├── show1.sh
├── shunit/
│ ├── .gitignore
│ ├── .travis.yml
│ ├── CODE_OF_CONDUCT.md
│ ├── LICENSE
│ ├── README.md
│ ├── doc/
│ │ ├── CHANGES-2.1.md
│ │ ├── RELEASE_NOTES-2.1.0.txt
│ │ ├── RELEASE_NOTES-2.1.1.txt
│ │ ├── RELEASE_NOTES-2.1.2.txt
│ │ ├── RELEASE_NOTES-2.1.3.txt
│ │ ├── RELEASE_NOTES-2.1.4.txt
│ │ ├── RELEASE_NOTES-2.1.5.txt
│ │ ├── RELEASE_NOTES-2.1.6.txt
│ │ ├── RELEASE_NOTES-2.1.7.md
│ │ ├── TODO.txt
│ │ ├── contributors.md
│ │ └── design_doc.txt
│ ├── examples/
│ │ ├── equality_test.sh
│ │ ├── lineno_test.sh
│ │ ├── math.inc
│ │ ├── math_test.sh
│ │ ├── mkdir_test.sh
│ │ ├── mock_file.sh
│ │ ├── mock_file_test.sh
│ │ ├── party_test.sh
│ │ └── suite_test.sh
│ ├── lib/
│ │ ├── shflags
│ │ └── versions
│ ├── shunit2
│ ├── shunit2_args_test.sh
│ ├── shunit2_asserts_test.sh
│ ├── shunit2_failures_test.sh
│ ├── shunit2_macros_test.sh
│ ├── shunit2_misc_test.sh
│ ├── shunit2_standalone_test.sh
│ ├── shunit2_test_helpers
│ └── test_runner
├── signal1.sh
├── signal2.sh
├── snapshot1.sh
├── start2.sh
├── start3.sh
├── start4.sh
├── stop1.sh
├── term1.sh
├── test-suite.sh
├── top1.sh
└── version1.sh
SYMBOL INDEX (1 symbols across 1 files) FILE: share/doc/pot/conf.py function setup (line 170) | def setup(app):
Condensed preview — 189 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,054K chars).
[
{
"path": ".github/ISSUE_TEMPLATE/bug_report.md",
"chars": 605,
"preview": "---\nname: Bug report\nabout: Report a bug you found\ntitle: \"[BUG]\"\nlabels: bug\nassignees: ''\n\n---\n\n**Describe the bug**\nA"
},
{
"path": ".github/ISSUE_TEMPLATE/feature_request.md",
"chars": 531,
"preview": "---\nname: Feature request\nabout: A nice to have\ntitle: ''\nlabels: feature\nassignees: ''\n\n---\n\n**Is your feature request "
},
{
"path": ".github/workflows/ci.yml",
"chars": 3236,
"preview": "name: Run CI\non:\n workflow_dispatch:\n push:\n branches: [ github-ci-action ]\n# pull_request:\n# branches: [ maste"
},
{
"path": ".github/workflows/main.yml",
"chars": 857,
"preview": "# This is a basic workflow to help you get started with Actions\n\nname: unit-test\n\n# Controls when the action will run. T"
},
{
"path": ".github/workflows/shellcheck.yml",
"chars": 296,
"preview": "name: Shellcheck\n\non: [ pull_request ]\n\njobs:\n shellcheck:\n name: Shellcheck\n runs-on: ubuntu-latest\n steps:\n "
},
{
"path": ".gitignore",
"chars": 190,
"preview": "/doc\n*.swp\n*~\n/etc/pot/pot.conf\n/etc/pot/flavours/*\n!/etc/pot/flavours/dns.sh\n!/etc/pot/flavours/dns\n!/etc/pot/flavours/"
},
{
"path": ".travis.yml",
"chars": 51,
"preview": "language: bash\nscript: cd tests && ./test-suite.sh\n"
},
{
"path": "CHANGELOG.md",
"chars": 30317,
"preview": "# Changelog\nAll notable changes to this project will be documented in this file.\n\nThe format is based on [Keep a Changel"
},
{
"path": "Jenkinsfile",
"chars": 193,
"preview": "pipeline {\n\tagent any\n\n\tenvironment {\n\t\tTERM = 'rxvt'\n\t}\n\n\tstages {\n\t\tstage('Test') {\n\t\t\tsteps {\n\t\t\t\tsh 'echo \"Hello Wor"
},
{
"path": "LICENSE",
"chars": 1516,
"preview": "BSD 3-Clause License\n\nCopyright (c) 2017, Luca Pizzamiglio\nAll rights reserved.\n\nRedistribution and use in source and bi"
},
{
"path": "README.md",
"chars": 5064,
"preview": "# THIS REPOSITORY IS NO LONGER ACTIVELY MAINTAINED, IT HAS MOVED TO https://codeberg.org/bsdpot/pot\n# pot\n\n[![build-badg"
},
{
"path": "bin/pot",
"chars": 6509,
"preview": "#!/bin/sh\n\n# Copyright (c) 2017, Luca Pizzamiglio <pizzamig@FreeBSD.org>\n# All rights reserved.\n#\n# Redistribution and u"
},
{
"path": "etc/pot/flavours/dns",
"chars": 38,
"preview": "set-attribute -A start-at-boot -V YES\n"
},
{
"path": "etc/pot/flavours/dns.sh",
"chars": 733,
"preview": "#!/bin/sh\n\npkg install -y dnsmasq\npkg install -y consul\npkg clean -ayq\n\nif [ ! -d /usr/local/etc/consul.d ]; then\n\tmkdir"
},
{
"path": "etc/pot/flavours/fbsd-update.sh",
"chars": 86,
"preview": "#!/bin/sh\n\nexport PAGER=/bin/cat\nfreebsd-update --not-running-from-cron fetch install\n"
},
{
"path": "etc/pot/flavours/slim.sh",
"chars": 917,
"preview": "#!/bin/sh\n\ndirs=\"/usr/share/bsdconfig /usr/share/doc /usr/share/dtrace /usr/share/examples /usr/share/man /usr/share/ope"
},
{
"path": "etc/pot/pot.conf.sample",
"chars": 1868,
"preview": "# pot configuration file\n\n# All datasets related to pot use the some zfs dataset as parent\n# With this variable, you can"
},
{
"path": "etc/pot/pot.default.conf",
"chars": 2314,
"preview": "# pot configuration file - default values\n\n# All datasets related to pot use the some zfs dataset as parent\n# With this "
},
{
"path": "etc/rc.d/pot",
"chars": 2095,
"preview": "#!/bin/sh\n\n# PROVIDE: pot\n# REQUIRE: NETWORKING LOGIN FILESYSTEM\n# BEFORE: securelevel\n# KEYWORD: shutdown nojail\n\n. /et"
},
{
"path": "etc/rc.d/pot_early",
"chars": 917,
"preview": "#!/bin/sh\n\n# PROVIDE: pot_early\n# REQUIRE: NETWORKING syslogd pf\n# BEFORE: ntpdate\n# KEYWORD: shutdown nojail\n\n. /etc/rc"
},
{
"path": "release.sh",
"chars": 722,
"preview": "#!/bin/sh\n\nprint_syntax() { echo \"$0\" X.Y.Z ; exit \"${1:-1}\"; }\n\nif [ -z \"$1\" ]; then\n\tprint_syntax\nfi\n\nif [ \"$1\" = \"$(e"
},
{
"path": "share/doc/pot/.gitignore",
"chars": 7,
"preview": "_build\n"
},
{
"path": "share/doc/pot/Description.md",
"chars": 250,
"preview": "DESCRIPTION\n-----------\nAnother container framework based on jails, to run FreeBSD containers on\nFreeBSD. Every running"
},
{
"path": "share/doc/pot/Images.md",
"chars": 6423,
"preview": "# Using `pot` images\n\nThis guide has the ambitious goal of explain how to create `pot` images, a feature that allows `po"
},
{
"path": "share/doc/pot/Installation.md",
"chars": 8193,
"preview": "# `pot` installation guide \n\nThis is a guide to prepare your FreeBSD installation to use the `pot` jail framework.\n\n**NO"
},
{
"path": "share/doc/pot/Makefile",
"chars": 600,
"preview": "# Minimal makefile for Sphinx documentation\n#\n\n# You can set these variables from the command line.\nSPHINXOPTS =\nSPHI"
},
{
"path": "share/doc/pot/QuickStart.md",
"chars": 16783,
"preview": "# QuickStart Guide on `pot`\n\nThis is an introduction at the usage of `pot`, a `jail(8)` wrapper based on ZFS and `pf(4)`"
},
{
"path": "share/doc/pot/Synopsis.md",
"chars": 36,
"preview": "SYNOPSIS\n--------\n\n`pot` SUBCOMMAND\n"
},
{
"path": "share/doc/pot/conf.py",
"chars": 5445,
"preview": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n#\n# pot documentation build configuration file, created by\n# sphinx-quick"
},
{
"path": "share/doc/pot/index.md",
"chars": 191,
"preview": "Contents\n--------\n\n* [Synopsis](Synopsis.md)\n* [Description](Description.md)\n* [QuickStart](QuickStart.md)\n* [Installati"
},
{
"path": "share/doc/pot/migration.md",
"chars": 979,
"preview": "## Manual migration handbook\n\n### Prerequisite\n\n* testing with single type pot\n* a snapshot is already present\n\n### A xz"
},
{
"path": "share/pot/add-dep.sh",
"chars": 1436,
"preview": "#!/bin/sh\n# shellcheck disable=SC3033,SC3040,SC3043\n:\n\nadd-dep-help()\n{\n\tcat <<-\"EOH\"\n\tpot add-dep [-hv] -p potname -P d"
},
{
"path": "share/pot/clone-fscomp.sh",
"chars": 1734,
"preview": "#!/bin/sh\n# shellcheck disable=SC3033,SC3040,SC3043\n:\n\nclone-fscomp-help()\n{\n\tcat <<-\"EOH\"\n\tpot clone-fscomp [-hv] -f fs"
},
{
"path": "share/pot/clone.sh",
"chars": 11027,
"preview": "#!/bin/sh\n# shellcheck disable=SC3033,SC3040,SC3043\n:\n\ntrap _cj_undo_clone TERM INT\n_set_pipefail\n\nclone-help()\n{\n\tcat <"
},
{
"path": "share/pot/common-flv.sh",
"chars": 4098,
"preview": "#!/bin/sh\n# shellcheck disable=SC3033,SC3040,SC3043\n\n# $1 flavour name\n_is_flavour()\n{\n\tlocal _flv_name\n\t_flv_name=\"$1\"\n"
},
{
"path": "share/pot/common.sh",
"chars": 28326,
"preview": "#!/bin/sh\n# shellcheck disable=SC2034,SC3033,SC3040,SC3043\n\n: \"${EXIT:=exit}\"\n: \"${ECHO:=echo}\"\n: \"${SED:=sed}\"\n\n_POT_RW"
},
{
"path": "share/pot/config.sh",
"chars": 1688,
"preview": "#!/bin/sh\n# shellcheck disable=SC3033,SC3040,SC3043\n\n: \"${_config_names:=\"fs_root zfs_root gateway syslogd pot_prefix fs"
},
{
"path": "share/pot/copy-in.sh",
"chars": 4853,
"preview": "#!/bin/sh\n# shellcheck disable=SC3033,SC3040,SC3043\n:\n\ncopy-in-help()\n{\n\tcat <<-\"EOH\"\n\tpot copy-in [-hv] -p pot -s sourc"
},
{
"path": "share/pot/copy-out.sh",
"chars": 3808,
"preview": "#!/bin/sh\n# shellcheck disable=SC3033,SC3040,SC3043\n:\n\ncopy-out-help()\n{\n\tcat <<-\"EOH\"\n\tpot copy-out [-hv] -p pot -s sou"
},
{
"path": "share/pot/create-base.sh",
"chars": 3837,
"preview": "#!/bin/sh\n# shellcheck disable=SC3033,SC3040,SC3043\n:\n\n# supported releases are defined in common.sh\n\ncreate-base-help()"
},
{
"path": "share/pot/create-fscomp.sh",
"chars": 912,
"preview": "#!/bin/sh\n# shellcheck disable=SC3033,SC3040,SC3043\n:\n\ncreate-fscomp-help()\n{\n\tcat <<-\"EOH\"\n\tpot create-fscomp [-hv] -f "
},
{
"path": "share/pot/create-private-bridge.sh",
"chars": 1482,
"preview": "#!/bin/sh\n# shellcheck disable=SC3033,SC3040,SC3043\n:\n\ncreate-private-bridge-help()\n{\n\tcat <<-\"EOH\"\n\tpot create-private-"
},
{
"path": "share/pot/create.sh",
"chars": 19879,
"preview": "#!/bin/sh\n# shellcheck disable=SC3033,SC3040,SC3043\n:\n\ntrap _cj_undo_create TERM INT\n_set_pipefail\n\ncreate-help()\n{\n\tcat"
},
{
"path": "share/pot/de-init.sh",
"chars": 1929,
"preview": "#!/bin/sh\n# shellcheck disable=SC3033,SC3040,SC3043\n:\n\nde-init-help()\n{\n\tcat <<-\"EOH\"\n\tpot de-init [-hmvf] [-p pf_file]\n"
},
{
"path": "share/pot/destroy.sh",
"chars": 8439,
"preview": "#!/bin/sh\n# shellcheck disable=SC3033,SC3040,SC3043\n:\n\ndestroy-help()\n{\n\tcat <<-\"EOH\"\n\tpot destroy [-hvFr] [-p potname|-"
},
{
"path": "share/pot/exec.sh",
"chars": 2932,
"preview": "#!/bin/sh\n# shellcheck disable=SC3033,SC3040,SC3043\n:\n\nexec-help()\n{\n\tcat <<-\"EOH\"\n\tpot exec [-hvdt] [-e var=value] [-u "
},
{
"path": "share/pot/export-ports.sh",
"chars": 2578,
"preview": "#!/bin/sh\n# shellcheck disable=SC3033,SC3040,SC3043\n:\n\nexport-ports-help()\n{\n\tcat <<-\"EOH\"\n\tpot export-ports configure e"
},
{
"path": "share/pot/export.sh",
"chars": 6369,
"preview": "#!/bin/sh\n# shellcheck disable=SC3033,SC3040,SC3043\n:\n\n# TODO\n# Add a way to directly upload the compressed file\n# Add a"
},
{
"path": "share/pot/get-attribute.sh",
"chars": 1602,
"preview": "#!/bin/sh\n# shellcheck disable=SC3033,SC3040,SC3043\n:\n\nget-attribute-help()\n{\n\tcat <<-EOH\n\tpot get-attribute [-hvq] -p p"
},
{
"path": "share/pot/get-rss.sh",
"chars": 2102,
"preview": "#!/bin/sh\n# shellcheck disable=SC3033,SC3040,SC3043\n:\n\nget-rss-help()\n{\n\tcat <<-\"EOH\"\n\tpot get-rss [-h] -p pot\n\t -h pri"
},
{
"path": "share/pot/help.sh",
"chars": 510,
"preview": "#!/bin/sh\n# shellcheck disable=SC3033,SC3040,SC3043\n\npot-help()\n{\n\tlocal _cmd _func\n\t_cmd=$1\n\tshift\n\tcase \"${_cmd}\" in\n\t"
},
{
"path": "share/pot/import.sh",
"chars": 6977,
"preview": "#!/bin/sh\n# shellcheck disable=SC3033,SC3040,SC3043\n:\n\n# TODO\n# add sha256 check on fetch pot and option to disable it\n#"
},
{
"path": "share/pot/info.sh",
"chars": 5949,
"preview": "#!/bin/sh\n# shellcheck disable=SC3033,SC3040,SC3043\n:\n\ninfo-help()\n{\n\tcat <<-\"EOH\"\n\tpot info [-hvqr] [-p pname|-B bname]"
},
{
"path": "share/pot/init.sh",
"chars": 4977,
"preview": "#!/bin/sh\n# shellcheck disable=SC3033,SC3040,SC3043\n:\n\n# TODO\n# check the return code of all commands\n\ninit-help()\n{\n\tca"
},
{
"path": "share/pot/last-run-stats.sh",
"chars": 777,
"preview": "#!/bin/sh\n# shellcheck disable=SC3033,SC3040,SC3043\n:\n\nlast-run-stats-help()\n{\n\tcat <<-\"EOH\"\n\tpot last-run-stats [-hv] ["
},
{
"path": "share/pot/list.sh",
"chars": 4527,
"preview": "#!/bin/sh\n# shellcheck disable=SC3033,SC3040,SC3043\n:\n\nlist-help()\n{\n\tcat <<-\"EOH\"\n\tpot list [-hpbfFa] [-qv]\n\t -h print"
},
{
"path": "share/pot/mount-in.sh",
"chars": 7469,
"preview": "#!/bin/sh\n# shellcheck disable=SC3033,SC3040,SC3043\n:\n\nmount-in-help()\n{\n\tcat <<-\"EOH\"\n\tpot mount-in [-hvwr] -p pot -m m"
},
{
"path": "share/pot/mount-out.sh",
"chars": 3381,
"preview": "#!/bin/sh\n# shellcheck disable=SC3033,SC3040,SC3043\n:\n\nmount-out-help()\n{\n\tcat <<-\"EOH\"\n\tpot mount-out [-hvwr] -p pot -m"
},
{
"path": "share/pot/network.sh",
"chars": 8260,
"preview": "#!/bin/sh\n# shellcheck disable=SC3033,SC3040,SC3043\n\n# tested\n_pot_bridge()\n{\n\t_pot_bridge_ipv4\n}\n\n_pot_bridge_ipv4()\n{\n"
},
{
"path": "share/pot/prepare.sh",
"chars": 6933,
"preview": "#!/bin/sh\n# shellcheck disable=SC3033,SC3040,SC3043\n:\n\nprepare-help()\n{\n\tcat <<-\"EOH\"\n\tpot prepare [-hvS] -p pot -U URL "
},
{
"path": "share/pot/prune.sh",
"chars": 2095,
"preview": "#!/bin/sh\n# shellcheck disable=SC3033,SC3040,SC3043\n\nprune-help()\n{\n\tcat <<-\"EOH\"\n\tpot prune [-hvq]\n\t -h print this hel"
},
{
"path": "share/pot/ps.sh",
"chars": 1004,
"preview": "#!/bin/sh\n# shellcheck disable=SC3033,SC3040,SC3043\n\nps-help()\n{\n\tcat <<-\"EOH\"\n\tpot ps [-hvq]\n\t -h print this help\n\t -"
},
{
"path": "share/pot/purge-snapshots.sh",
"chars": 2385,
"preview": "#!/bin/sh\n# shellcheck disable=SC3033,SC3040,SC3043\n:\n\npurge-snapshots-help()\n{\n\tcat <<-\"EOH\"\n\tpot purge-snapshots [-hva"
},
{
"path": "share/pot/rename.sh",
"chars": 4504,
"preview": "#!/bin/sh\n# shellcheck disable=SC3033,SC3040,SC3043\n:\n\nrename-help()\n{\n\tcat <<-\"EOH\"\n\tpot rename [-hv] -p oldname -n new"
},
{
"path": "share/pot/revert.sh",
"chars": 2366,
"preview": "#!/bin/sh\n# shellcheck disable=SC3033,SC3040,SC3043\n:\n\nrevert-help()\n{\n\tcat <<-\"EOH\"\n\tpot revert [-hv] -p potname|-f fsc"
},
{
"path": "share/pot/set-attribute.sh",
"chars": 4123,
"preview": "#!/bin/sh\n# shellcheck disable=SC3033,SC3040,SC3043\n:\n\nset-attribute-help()\n{\n\tcat <<-EOH\n\tpot set-attribute [-hv] -p po"
},
{
"path": "share/pot/set-cmd.sh",
"chars": 901,
"preview": "#!/bin/sh\n# shellcheck disable=SC3033,SC3040,SC3043\n:\n\nset-cmd-help() {\n\tcat <<-\"EOH\"\n\tpot set-cmd [-hv] -p pot -c cmd\n\t"
},
{
"path": "share/pot/set-env.sh",
"chars": 1835,
"preview": "#!/bin/sh\n# shellcheck disable=SC3033,SC3040,SC3043\n:\n\nset-env-help() {\n\tcat <<-\"EOH\"\n\tpot set-env [-hv] -p pot -E env\n\t"
},
{
"path": "share/pot/set-hook.sh",
"chars": 2084,
"preview": "#!/bin/sh\n# shellcheck disable=SC3033,SC3040,SC3043\n:\n\nset-hook-help() {\n\tcat <<-\"EOH\"\n\tpot set-hook [-hv] -p pot [-s ho"
},
{
"path": "share/pot/set-hosts.sh",
"chars": 2092,
"preview": "#!/bin/sh\n# shellcheck disable=SC3033,SC3040,SC3043\n:\n\nset-hosts-help() {\n\tcat <<-\"EOH\"\n\tpot set-hosts [-hv] -p pot -H h"
},
{
"path": "share/pot/set-rss.sh",
"chars": 2430,
"preview": "#!/bin/sh\n# shellcheck disable=SC3033,SC3040,SC3043\n:\n\nset-rss-help()\n{\n\tcat <<-\"EOH\"\n\tpot set-rss [-hv] -p pot [-C cpus"
},
{
"path": "share/pot/set-status.sh",
"chars": 3410,
"preview": "#!/bin/sh\n# shellcheck disable=SC3033,SC3040,SC3043\n:\n\n: \"${_POT_INTERNAL_STATUS:=\"starting doa started stopping stopped"
},
{
"path": "share/pot/show.sh",
"chars": 4096,
"preview": "#!/bin/sh\n# shellcheck disable=SC3033,SC3040,SC3043\n:\n\nshow-help()\n{\n\tcat <<-\"EOH\"\n\tpot show [-hvq] [-a|-r|-p potname]\n\t"
},
{
"path": "share/pot/signal.sh",
"chars": 4042,
"preview": "#!/bin/sh\n# shellcheck disable=SC3033,SC3040,SC3043\n:\n\nsignal-help()\n{\n\tcat <<-\"EOH\"\n\tpot signal [-hvflC] [-s signal] [-"
},
{
"path": "share/pot/snapshot.sh",
"chars": 2046,
"preview": "#!/bin/sh\n# shellcheck disable=SC3033,SC3040,SC3043\n:\n\nsnapshot-help()\n{\n\tcat <<-\"EOH\"\n\tpot snapshot [-hv] -p potname|-f"
},
{
"path": "share/pot/start.sh",
"chars": 25032,
"preview": "#!/bin/sh\n# shellcheck disable=SC3033,SC3040,SC3043\n:\n\nstart-help()\n{\n\tcat <<-\"EOH\"\n\tpot start [-h] -p potname [pname]\n\t"
},
{
"path": "share/pot/stop.sh",
"chars": 6246,
"preview": "#!/bin/sh\n# shellcheck disable=SC3033,SC3040,SC3043\n:\n\nstop-help()\n{\n\tcat <<-\"EOH\"\n\tpot stop [-hv] -p potname | potname\n"
},
{
"path": "share/pot/term.sh",
"chars": 1436,
"preview": "#!/bin/sh\n# shellcheck disable=SC3033,SC3040,SC3043\n:\n\nterm-help()\n{\n\tcat <<-\"EOH\"\n\tpot term [-hvf] -p potname [pname]\n\t"
},
{
"path": "share/pot/top.sh",
"chars": 677,
"preview": "#!/bin/sh\n# shellcheck disable=SC3033,SC3040,SC3043\n:\n\ntop-help()\n{\n\tcat <<-\"EOH\"\n\tpot top [-h] -p pot\n\t -h print this "
},
{
"path": "share/pot/update-config.sh",
"chars": 5124,
"preview": "#!/bin/sh\n# shellcheck disable=SC3033,SC3040,SC3043\n:\n\nupdate-config-help()\n{\n\tcat <<-\"EOH\"\n\tpot update-config [-h] -p p"
},
{
"path": "share/pot/version.sh",
"chars": 560,
"preview": "#!/bin/sh\n# shellcheck disable=SC3033,SC3040,SC3043\n:\n\nversion-help()\n{\n\tcat <<-\"EOH\"\n\tpot version [-hvq]\n\t -h print th"
},
{
"path": "share/pot/vnet-start.sh",
"chars": 5258,
"preview": "#!/bin/sh\n# shellcheck disable=SC3033,SC3040,SC3043\n:\n\nvnet-start-help()\n{\n\tcat <<-\"EOH\"\n\tpot vnet-start [-hv] [-B bridg"
},
{
"path": "share/zsh/site-functions/_pot",
"chars": 12799,
"preview": "#compdef pot\n\n: ${POT_FS_ROOT:=$( pot config -qg fs_root )}\n\n_pot_pots() {\n _values \"pot pots\" ${${(f)\"$(${servic"
},
{
"path": "tests/CI/resolv.conf-dual",
"chars": 103,
"preview": "nameserver 1.1.1.1\nnameserver 1.0.0.1\nnameserver 2606:4700:4700::1111\nnameserver 2606:4700:4700::1001\n\n"
},
{
"path": "tests/CI/resolv.conf-ipv4",
"chars": 39,
"preview": "nameserver 1.1.1.1\nnameserver 1.0.0.1\n\n"
},
{
"path": "tests/CI/resolv.conf-ipv6",
"chars": 65,
"preview": "nameserver 2606:4700:4700::1111\nnameserver 2606:4700:4700::1001\n\n"
},
{
"path": "tests/CI/run.sh",
"chars": 11215,
"preview": "#!/bin/sh\n\nexport POT_PATH=$( realpath $( dirname $(realpath $0))/../..)\nexport PATH=$POT_PATH/bin:$PATH\ntimestamp=\"$(da"
},
{
"path": "tests/add-dep1.sh",
"chars": 3114,
"preview": "#!/bin/sh\n\n# system utilities stubs\n\n# UUT\n. ../share/pot/add-dep.sh\n\n# common stubs\n. common-stub.sh\n\n# app specific st"
},
{
"path": "tests/clone-fscomp1.sh",
"chars": 3424,
"preview": "#!/bin/sh\n\n# system utilities stubs\n\n# UUT\n. ../share/pot/clone-fscomp.sh\n\n# common stubs\n. common-stub.sh\n\n_zfs_dataset"
},
{
"path": "tests/clone1.sh",
"chars": 15408,
"preview": "#!/bin/sh\n\n# system utilities stubs\npotnet()\n{\n\t# no monitor, potnet is called in a subshell\n\tif [ \"$1\" = \"next\" ]; then"
},
{
"path": "tests/clone2.sh",
"chars": 10004,
"preview": "#!/bin/sh\n\n# system utilities stubs\nzfs()\n{\n\t__monitor ZFS \"$@\"\n}\n\nECHO=echo_stub\necho_stub()\n{\n\t__monitor ECHO \"$@\"\n}\n\n"
},
{
"path": "tests/common-flv1.sh",
"chars": 1288,
"preview": "#!/bin/sh\n\n# system utilities stubs\n. monitor.sh\n\n# UUT\n. ../share/pot/common-flv.sh\n\n# app specific stubs\n\n_get_flavour"
},
{
"path": "tests/common-stub.sh",
"chars": 5822,
"preview": "#!/bin/sh\n. ../share/pot/common.sh\n. ../share/pot/common-flv.sh\n. ../share/pot/network.sh\nEXIT=\"return\"\n\n# common stubs\n"
},
{
"path": "tests/common-zfs1.sh",
"chars": 1118,
"preview": "#!/bin/sh\n\n# system utilities stubs\n\nzfs()\n{\n\tif [ \"$2\" = \"zfs-dataset\" ]; then\n\t\treturn 0 # true\n\tfi\n\tif [ \"$2\" = \"-H\" "
},
{
"path": "tests/common-zfs2.sh",
"chars": 733,
"preview": "#!/bin/sh\n\n. monitor.sh\n# system utilities stubs\n\nzfs()\n{\n\t__monitor ZFS \"$@\"\n}\n\ndate()\n{\n\techo \"123454321\"\n}\n\n# UUT\n. ."
},
{
"path": "tests/common1.sh",
"chars": 3978,
"preview": "#!/bin/sh\n\n# system utilities stubs\n. monitor.sh\n\nmount()\n{\n\tcat << EOF--\nzroot on /zroot (zfs, local, noatime, nfsv4acl"
},
{
"path": "tests/common2.sh",
"chars": 2735,
"preview": "#!/bin/sh\n\n# system utilities stubs\n\nif [ \"$(uname)\" = \"Linux\" ]; then\n\tTEST=/usr/bin/[\nelse\n\tTEST=/bin/[\nfi\n\n[()\n{\n\tif "
},
{
"path": "tests/common4.sh",
"chars": 817,
"preview": "#!/bin/sh\n\n# system utilities stubs\n\n# UUT\n. ../share/pot/common.sh\n\n# common stubs\n. ./monitor.sh\n\n_qerror()\n{\n\t__monit"
},
{
"path": "tests/common5.sh",
"chars": 5472,
"preview": "#!/bin/sh\n\n# system utilities stubs\n\nif [ \"$(uname)\" = \"Linux\" ]; then\n\tTEST=/usr/bin/[\nelse\n\tTEST=/bin/[\nfi\n\n[()\n{\n\t#ec"
},
{
"path": "tests/common6.sh",
"chars": 388,
"preview": "#!/bin/sh\n\n# system utilities stubs\n\n# UUT\n. ../share/pot/common.sh\n\n# common stubs\n. conf-stub.sh\n\ntest_get_conf_vnet_0"
},
{
"path": "tests/common7.sh",
"chars": 2814,
"preview": "#!/bin/sh\n\n# system utilities stubs\n\nfind()\n{\n\tcat << MANIFEST-EOF\n/usr/local/share/freebsd/MANIFESTS/amd64-amd64-12.0-R"
},
{
"path": "tests/common8.sh",
"chars": 621,
"preview": "#!/bin/sh\n\n# system utilities stubs\n\n# UUT\n. ../share/pot/common.sh\n\ntest_is_natural_number_001()\n{\n\t_is_natural_number "
},
{
"path": "tests/conf-stub.sh",
"chars": 2467,
"preview": "#!/bin/sh\n\nconf_setUp()\n{\n\tPOT_FS_ROOT=/tmp\n\tPOT_ZFS_ROOT=zpot\n\n\t/bin/mkdir -p /tmp/jails/test-pot/conf\n\t{\n\t\techo \"zpot/"
},
{
"path": "tests/config1.sh",
"chars": 1807,
"preview": "#!/bin/sh\n\n# system utilities stubs\n\n# UUT\n. ../share/pot/config.sh\n\n. ../share/pot/common.sh\n# common stubs\n. common-st"
},
{
"path": "tests/copy-in1.sh",
"chars": 7943,
"preview": "#!/bin/sh\n\n# system utilities stubs\n\nif [ \"$(uname)\" = \"Linux\" ]; then\n\tTEST=/usr/bin/[\nelse\n\tTEST=/bin/[\nfi\n\n[()\n{\n\tif "
},
{
"path": "tests/copy-out1.sh",
"chars": 7938,
"preview": "#!/bin/sh\n\n# system utilities stubs\n\nif [ \"$(uname)\" = \"Linux\" ]; then\n\tTEST=/usr/bin/[\nelse\n\tTEST=/bin/[\nfi\n\n[()\n{\n\tif "
},
{
"path": "tests/create-base1.sh",
"chars": 6151,
"preview": "#!/bin/sh\n\n# system utilities stubs\n\n# UUT\n. ../share/pot/create-base.sh\n\n# common stubs\n. common-stub.sh\n\n_is_init()\n{\n"
},
{
"path": "tests/create-fscomp1.sh",
"chars": 2332,
"preview": "#!/bin/sh\n\n# system utilities stubs\nzfs()\n{\n\t__monitor ZFS \"$@\"\n\treturn 0 # true\n}\n\n# UUT\n. ../share/pot/create-fscomp.s"
},
{
"path": "tests/create-private-bridge1.sh",
"chars": 2542,
"preview": "#!/bin/sh\n\n# system utilities stubs\nmkdir()\n{\n\t__monitor MKDIR \"$@\"\n}\n\n# UUT\n. ../share/pot/create-private-bridge.sh\n\n# "
},
{
"path": "tests/create1.sh",
"chars": 42311,
"preview": "#!/bin/sh\n\n# system utilities stubs\npotnet()\n{\n\t__monitor POTNET \"$@\"\n\tif [ \"$1\" = \"next\" ]; then\n\t\techo \"10.192.123.123"
},
{
"path": "tests/create2.sh",
"chars": 9858,
"preview": "#!/bin/sh\n\n# system utilities stubs\nzfs()\n{\n\t__monitor ZFS \"$@\"\n}\n\nECHO=echo_stub\necho_stub()\n{\n\t__monitor ECHO \"$@\"\n}\n\n"
},
{
"path": "tests/create3.sh",
"chars": 20247,
"preview": "#!/bin/sh\n\n# system utilities stubs\nmkdir()\n{\n\t__monitor MKDIR \"$@\"\n\t/bin/mkdir \"$@\"\n}\n\nSED=sed_stub\nsed_stub()\n{\n\t__mon"
},
{
"path": "tests/destroy1.sh",
"chars": 8793,
"preview": "#!/bin/sh\n\n# system utilities stubs\n\nls()\n{\n\tcat << LS_EOL\n/opt/pot/jails/base-11_1/\n/opt/pot/jails/test-pot/\n/opt/pot/j"
},
{
"path": "tests/export-ports1.sh",
"chars": 6736,
"preview": "#!/bin/sh\n\n# system utilities stubs\n\n# UUT\n. ../share/pot/export-ports.sh\n\n# common stubs\n. common-stub.sh\n\n# app specif"
},
{
"path": "tests/export1.sh",
"chars": 8990,
"preview": "#!/bin/sh\n\n# system utilities stubs\n\n# UUT\n. ../share/pot/export.sh\n\n. ../share/pot/common.sh\n# common stubs\n. common-st"
},
{
"path": "tests/get-rss1.sh",
"chars": 1884,
"preview": "#!/bin/sh\n\n# system utilities stubs\n\n# UUT\n. ../share/pot/get-rss.sh\n\n. ../share/pot/common.sh\n# common stubs\n. common-s"
},
{
"path": "tests/import1.sh",
"chars": 6219,
"preview": "#!/bin/sh\n\n# system utilities stubs\n\n# UUT\n. ../share/pot/import.sh\n\n. ../share/pot/common.sh\n\n# common stubs\n. common-s"
},
{
"path": "tests/info1.sh",
"chars": 5105,
"preview": "#!/bin/sh\n\n# system utilities stubs\n\n# UUT\n. ../share/pot/info.sh\n\n. ../share/pot/common.sh\n# common stubs\n. common-stub"
},
{
"path": "tests/info2.sh",
"chars": 3203,
"preview": "#!/bin/sh\n\n# system utilities stubs\n\n# UUT\n. ../share/pot/info.sh\n\n. ../share/pot/common.sh\n# common stubs\n\n_get_pot_net"
},
{
"path": "tests/list1.sh",
"chars": 7978,
"preview": "#!/bin/sh\n\n# system utilities stubs\n\n# UUT\n. ../share/pot/list.sh\n\n. ../share/pot/common.sh\n# common stubs\n. common-stub"
},
{
"path": "tests/list2.sh",
"chars": 1146,
"preview": "#!/bin/sh\n\n# system utilities stubs\n\n# UUT\n. ../share/pot/list.sh\n\n. ../share/pot/common.sh\n# common stubs\n. common-stub"
},
{
"path": "tests/monitor.sh",
"chars": 2060,
"preview": "#!/bin/sh\n# shellcheck disable=SC3043\n\nif [ -z \"$POT_MONITOR_TMP\" ]; then\n\tif [ \"$(command uname)\" = \"Linux\" ]; then\n\t\tP"
},
{
"path": "tests/mount-in1.sh",
"chars": 20896,
"preview": "#!/bin/sh\n\n# system utilities stubs\n\nif [ \"$(uname)\" = \"Linux\" ]; then\n\tTEST=/usr/bin/[\nelse\n\tTEST=/bin/[\nfi\n\n[()\n{\n\tif "
},
{
"path": "tests/mount-out1.sh",
"chars": 3131,
"preview": "#!/bin/sh\n\n# system utilities stubs\n\nif [ \"$(uname)\" = \"Linux\" ]; then\n\tTEST=/usr/bin/[\nelse\n\tTEST=/bin/[\nfi\n\n[()\n{\n\tif "
},
{
"path": "tests/network1.sh",
"chars": 26635,
"preview": "#!/bin/sh\n\n# system utilities stubs\nifconfig() {\n\tif [ -z \"$1\" ]; then\n\t\tcat << EOF--\nem0: flags=8843<UP,BROADCAST,RUNNI"
},
{
"path": "tests/pipefail-stub.sh",
"chars": 361,
"preview": "#!/bin/sh\n\n_set_pipefail()\n{\n\tlocal _major _version\n\tif [ \"$(uname)\" = \"Linux\" ]; then\n\t\tset -o pipefail\n\t\treturn\n\tfi\n\t_"
},
{
"path": "tests/ps1.sh",
"chars": 1231,
"preview": "#!/bin/sh\n\n# system utilities stubs\n\n# UUT\n. ../share/pot/ps.sh\n\n. ../share/pot/common.sh\n# common stubs\n. common-stub.s"
},
{
"path": "tests/rename1.sh",
"chars": 4717,
"preview": "#!/bin/sh\n\n# system utilities stubs\n\n# UUT\n. ../share/pot/rename.sh\n\n# common stubs\n. common-stub.sh\n\n# app specific stu"
},
{
"path": "tests/rename2.sh",
"chars": 984,
"preview": "#!/bin/sh\n\n# system utilities stubs\nSED=sed_stub\nsed_stub()\n{\n\tif [ \"$(uname)\" = \"Linux\" ]; then\n\t\tsed -i'' \"$3\" \"$4\" \"$"
},
{
"path": "tests/rename3.sh",
"chars": 5036,
"preview": "#!/bin/sh\n\n# system utilities stubs\nzfs()\n{\n\t__monitor ZFS \"$@\"\n}\n\n# UUT\n. ../share/pot/rename.sh\n\n# common stubs\n. comm"
},
{
"path": "tests/rename4.sh",
"chars": 1207,
"preview": "#!/bin/sh\n\n# system utilities stubs\nls()\n{\n\tcat << LS_EOL\n/opt/pot/jails/test-pot/\n/opt/pot/jails/test-pot-2/\n/opt/pot/j"
},
{
"path": "tests/revert1.sh",
"chars": 7736,
"preview": "#!/bin/sh\n\n# system utilities stubs\n\n# UUT\n. ../share/pot/revert.sh\n\n# common stubs\n. common-stub.sh\n\n# app specific stu"
},
{
"path": "tests/set-attr1.sh",
"chars": 7233,
"preview": "#!/bin/sh\n\n# system utilities stubs\n\n# UUT\n. ../share/pot/set-attribute.sh\n\n# common stubs\n. common-stub.sh\n\n# app speci"
},
{
"path": "tests/set-attr2.sh",
"chars": 686,
"preview": "#!/bin/sh\n\n# system utilities stubs\n\n# UUT\n. ../share/pot/set-attribute.sh\n\n# common stubs\n. common-stub.sh\n\n# app speci"
},
{
"path": "tests/set-cmd1.sh",
"chars": 2570,
"preview": "#!/bin/sh\n\n# system utilities stubs\n\n# UUT\n. ../share/pot/set-cmd.sh\n\n# common stubs\n. common-stub.sh\n\n# app specific st"
},
{
"path": "tests/set-env1.sh",
"chars": 10013,
"preview": "#!/bin/sh\n\n# system utilities stubs\n\n# UUT\n. ../share/pot/set-env.sh\n\n# common stubs\n. common-stub.sh\n\n# app specific st"
},
{
"path": "tests/set-env2.sh",
"chars": 3476,
"preview": "#!/bin/sh\n\n# system utilities stubs\nSED=sed_stub\nsed_stub()\n{\n\tif [ \"$(uname)\" = \"Linux\" ]; then\n\t\tsed -i'' \"$3\" \"$4\"\n\te"
},
{
"path": "tests/set-hook1.sh",
"chars": 6376,
"preview": "#!/bin/sh\n\n# system utilities stubs\npotnet()\n{\n\tcase \"$4\" in\n\t\t\"10.1.2.3\"|\"10.1.2.4\"|\\\n\t\t\"fe00::2\"|\"::1\")\n\t\treturn 0 # t"
},
{
"path": "tests/set-hosts1.sh",
"chars": 6958,
"preview": "#!/bin/sh\n\n# system utilities stubs\npotnet()\n{\n\tcase \"$4\" in\n\t\t\"10.1.2.3\"|\"10.1.2.4\"|\\\n\t\t\"fe00::2\"|\"::1\")\n\t\treturn 0 # t"
},
{
"path": "tests/set-rss1.sh",
"chars": 4868,
"preview": "#!/bin/sh\n\n# system utilities stubs\n\n# UUT\n. ../share/pot/set-rss.sh\n\n# common stubs\n. common-stub.sh\n\n# app specific st"
},
{
"path": "tests/show1.sh",
"chars": 4877,
"preview": "#!/bin/sh\n\n# system utilities stubs\n\n# UUT\n. ../share/pot/show.sh\n\n. ../share/pot/common.sh\n# common stubs\n. common-stub"
},
{
"path": "tests/shunit/.gitignore",
"chars": 49,
"preview": "# Hidden files generated by macOS.\n.DS_Store\n._*\n"
},
{
"path": "tests/shunit/.travis.yml",
"chars": 472,
"preview": "language: bash\n\nenv:\n - SHUNIT_COLOR='always'\n\nscript:\n # Execute the unit tests.\n - ./test_runner\n\nos:\n - linux\n -"
},
{
"path": "tests/shunit/CODE_OF_CONDUCT.md",
"chars": 3220,
"preview": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, w"
},
{
"path": "tests/shunit/LICENSE",
"chars": 11357,
"preview": " Apache License\n Version 2.0, January 2004\n "
},
{
"path": "tests/shunit/README.md",
"chars": 22955,
"preview": "# shUnit2\n\nshUnit2 is a [xUnit](http://en.wikipedia.org/wiki/XUnit) unit test framework for\nBourne based shell scripts, "
},
{
"path": "tests/shunit/doc/CHANGES-2.1.md",
"chars": 8558,
"preview": "# shUnit2 2.1.x Changes\n\n## Changes with 2.1.8\n\n### New\n\nIssue #29. Add support for user defined prefix for test names. "
},
{
"path": "tests/shunit/doc/RELEASE_NOTES-2.1.0.txt",
"chars": 2247,
"preview": "Release Notes for shUnit2 2.1.0\n===============================\n\nThis release was branched from shUnit2 2.0.1. It mostly"
},
{
"path": "tests/shunit/doc/RELEASE_NOTES-2.1.1.txt",
"chars": 1634,
"preview": "Release Notes for shUnit2 2.1.1\n===============================\n\nThis is mainly a bug fix release, but it also incorpora"
},
{
"path": "tests/shunit/doc/RELEASE_NOTES-2.1.2.txt",
"chars": 1696,
"preview": "Release Notes for shUnit2 2.1.2\n===============================\n\nThis release adds initial support for the zsh shell. Du"
},
{
"path": "tests/shunit/doc/RELEASE_NOTES-2.1.3.txt",
"chars": 1570,
"preview": "Release Notes for shUnit2 2.1.3\n===============================\n\nThis release is minor feature release. It improves supp"
},
{
"path": "tests/shunit/doc/RELEASE_NOTES-2.1.4.txt",
"chars": 1716,
"preview": "Release Notes for shUnit2 2.1.4\n===============================\n\nThis release contains lots of bug fixes and changes. Mo"
},
{
"path": "tests/shunit/doc/RELEASE_NOTES-2.1.5.txt",
"chars": 2862,
"preview": "Release Notes for shUnit2 2.1.5\n===============================\n\nThis release contains several bug fixes and changes. Ad"
},
{
"path": "tests/shunit/doc/RELEASE_NOTES-2.1.6.txt",
"chars": 2392,
"preview": "Release Notes for shUnit2 2.1.6\n===============================\n\nThis release contains bug fixes and changes. It is also"
},
{
"path": "tests/shunit/doc/RELEASE_NOTES-2.1.7.md",
"chars": 1579,
"preview": "# shUnit2 2.1.7 Release Notes\n\nhttps://github.com/kward/shunit2\n\nThis release contains bug fixes and enhancements. It is"
},
{
"path": "tests/shunit/doc/TODO.txt",
"chars": 486,
"preview": "Make it possible to execute a single test by passing the name of the test on\nthe command line\n\nAdd support for '--random"
},
{
"path": "tests/shunit/doc/contributors.md",
"chars": 447,
"preview": "The original author of shunit2 is Kate Ward. The following people have\ncontributed in some way or another to shunit2.\n\n-"
},
{
"path": "tests/shunit/doc/design_doc.txt",
"chars": 1454,
"preview": "Design Doc for shUnit\n\nshUnit is based upon JUnit. The initial ideas for the script came from the book\n\"Pragmatic Unit T"
},
{
"path": "tests/shunit/examples/equality_test.sh",
"chars": 122,
"preview": "#! /bin/sh\n# file: examples/equality_test.sh\n\ntestEquality() {\n assertEquals 1 1\n}\n\n# Load and run shUnit2.\n. ../shunit"
},
{
"path": "tests/shunit/examples/lineno_test.sh",
"chars": 402,
"preview": "#! /bin/sh\n# file: examples/lineno_test.sh\n\ntestLineNo() {\n # This assert will have line numbers included (e.g. \"ASSERT"
},
{
"path": "tests/shunit/examples/math.inc",
"chars": 149,
"preview": "# available as examples/math.inc\n\nadd_generic()\n{\n num_a=$1\n num_b=$2\n\n expr $1 + $2\n}\n\nadd_bash()\n{\n num_a=$1\n num"
},
{
"path": "tests/shunit/examples/math_test.sh",
"chars": 454,
"preview": "#! /bin/sh\n# file: examples/math_test.sh\n\ntestAdding() {\n result=`add_generic 1 2`\n assertEquals \\\n \"the result o"
},
{
"path": "tests/shunit/examples/mkdir_test.sh",
"chars": 2264,
"preview": "#!/bin/sh\n# vim:et:ft=sh:sts=2:sw=2\n#\n# Copyright 2008-2019 Kate Ward. All Rights Reserved.\n# Released under the Apache "
},
{
"path": "tests/shunit/examples/mock_file.sh",
"chars": 2498,
"preview": "#!/bin/sh\n#\n# shUnit2 example for mocking files.\n#\n# This example demonstrates two different mechanisms for mocking file"
},
{
"path": "tests/shunit/examples/mock_file_test.sh",
"chars": 897,
"preview": "#!/bin/sh\n#\n# shUnit2 example for mocking files.\n\nMOCK_PASSWD='' # This will be overridden in oneTimeSetUp().\n\ntest_roo"
},
{
"path": "tests/shunit/examples/party_test.sh",
"chars": 472,
"preview": "#! /bin/sh\n# file: examples/party_test.sh\n#\n# This test is mostly for fun. Technically, it is a bad example of a unit te"
},
{
"path": "tests/shunit/examples/suite_test.sh",
"chars": 986,
"preview": "#!/bin/sh\n# file: examples/suite_test.sh\n#\n# This test demonstrates the use of suites. Note: the suite functionality is\n"
},
{
"path": "tests/shunit/lib/shflags",
"chars": 38349,
"preview": "# vim:et:ft=sh:sts=2:sw=2\n#\n# Copyright 2008-2017 Kate Ward. All Rights Reserved.\n# Released under the Apache License 2."
},
{
"path": "tests/shunit/lib/versions",
"chars": 8025,
"preview": "#! /bin/sh\n# vim:et:ft=sh:sts=2:sw=2\n#\n# Versions determines the versions of all installed shells.\n#\n# Copyright 2008-20"
},
{
"path": "tests/shunit/shunit2",
"chars": 39509,
"preview": "#! /bin/sh\n# vim:et:ft=sh:sts=2:sw=2\n#\n# Copyright 2008-2019 Kate Ward. All Rights Reserved.\n# Released under the Apache"
},
{
"path": "tests/shunit/shunit2_args_test.sh",
"chars": 2055,
"preview": "#!/bin/sh\n#\n# shunit2 unit test for running subset(s) of tests based upon command line arguments.\n# Also shows how non-d"
},
{
"path": "tests/shunit/shunit2_asserts_test.sh",
"chars": 9280,
"preview": "#! /bin/sh\n# vim:et:ft=sh:sts=2:sw=2\n#\n# shunit2 unit test for assert functions.\n#\n# Copyright 2008-2017 Kate Ward. All "
},
{
"path": "tests/shunit/shunit2_failures_test.sh",
"chars": 2734,
"preview": "#! /bin/sh\n# vim:et:ft=sh:sts=2:sw=2\n#\n# Copyright 2008-2019 Kate Ward. All Rights Reserved.\n# Released under the Apache"
},
{
"path": "tests/shunit/shunit2_macros_test.sh",
"chars": 8111,
"preview": "#! /bin/sh\n# vim:et:ft=sh:sts=2:sw=2\n#\n# shunit2 unit test for macros.\n#\n# Copyright 2008-2017 Kate Ward. All Rights Res"
},
{
"path": "tests/shunit/shunit2_misc_test.sh",
"chars": 9395,
"preview": "#! /bin/sh\n# vim:et:ft=sh:sts=2:sw=2\n#\n# shUnit2 unit tests of miscellaneous things\n#\n# Copyright 2008-2018 Kate Ward. A"
},
{
"path": "tests/shunit/shunit2_standalone_test.sh",
"chars": 985,
"preview": "#! /bin/sh\n# vim:et:ft=sh:sts=2:sw=2\n#\n# shUnit2 unit test for standalone operation.\n#\n# Copyright 2010-2017 Kate Ward. "
},
{
"path": "tests/shunit/shunit2_test_helpers",
"chars": 6806,
"preview": "# vim:et:ft=sh:sts=2:sw=2\n#\n# shUnit2 unit test common functions\n#\n# Copyright 2008 Kate Ward. All Rights Reserved.\n# Re"
},
{
"path": "tests/shunit/test_runner",
"chars": 4649,
"preview": "#! /bin/sh\n# vim:et:ft=sh:sts=2:sw=2\n#\n# Unit test suite runner.\n#\n# Copyright 2008-2018 Kate Ward. All Rights Reserved."
},
{
"path": "tests/signal1.sh",
"chars": 5261,
"preview": "#!/bin/sh\n\n# system utilities stubs\n\n# UUT\n. ../share/pot/signal.sh\n\n. ../share/pot/common.sh\n# common stubs\n. common-st"
},
{
"path": "tests/signal2.sh",
"chars": 2711,
"preview": "#!/bin/sh\n\n# system utilities stubs\npkill()\n{\n\t__monitor PKILL \"$@\"\n}\n\npgrep()\n{\n\t__monitor PGREP \"$@\"\n}\n\nmktemp()\n{\n\t__"
},
{
"path": "tests/snapshot1.sh",
"chars": 12994,
"preview": "#!/bin/sh\n\n# system utilities stubs\n\n# UUT\n. ../share/pot/snapshot.sh\n\n# common stubs\n. common-stub.sh\n\n# app specific s"
},
{
"path": "tests/start2.sh",
"chars": 2471,
"preview": "#!/bin/sh\n\n: ${MKTEMP_FILE:=/tmp/pot_pfrules_test}\n# system utilities stubs\npfctl()\n{\n\t__monitor PFCTL \"$@\"\n}\n\nmktemp()\n"
},
{
"path": "tests/start3.sh",
"chars": 5794,
"preview": "#!/bin/sh\n\n# system utilities stubs\npfctl()\n{\n\t__monitor PFCTL \"$@\"\n}\n\nSED=sed_stub\nsed_stub()\n{\n\tif [ \"$(uname)\" = \"Lin"
},
{
"path": "tests/start4.sh",
"chars": 5713,
"preview": "#!/bin/sh\n\n# system utilities stubs\npotnet()\n{\n\tif [ -z \"$3\" ]; then\n\t\t# public bridge\n\t\techo \"10.1.2.3 test-pot-2\"\n\t\tec"
},
{
"path": "tests/stop1.sh",
"chars": 2788,
"preview": "#!/bin/sh\n\n# system utilities stubs\n\nlockf()\n{\n\treturn 0\n}\n# UUT\n. ../share/pot/stop.sh\n\n. ../share/pot/common.sh\n# comm"
},
{
"path": "tests/term1.sh",
"chars": 2757,
"preview": "#!/bin/sh\n\n# system utilities stubs\n\n# UUT\n. ../share/pot/term.sh\n\n. ../share/pot/common.sh\n# common stubs\n. common-stub"
},
{
"path": "tests/test-suite.sh",
"chars": 846,
"preview": "#!/bin/sh\n\nDOIT=\nSHL=\"sh\"\nif [ \"$(uname)\" = \"Linux\" ]; then\n\t# using bash explicitely because of travis unkowns about /b"
},
{
"path": "tests/top1.sh",
"chars": 1994,
"preview": "#!/bin/sh\n\n# system utilities stubs\n\ntop()\n{\n\t__monitor TOP \"$@\"\n}\n\n# UUT\n. ../share/pot/top.sh\n\n. ../share/pot/common.s"
},
{
"path": "tests/version1.sh",
"chars": 968,
"preview": "#!/bin/sh\n\n# system utilities stubs\n\n# UUT\n. ../share/pot/version.sh\n\n. ../share/pot/common.sh\n# common stubs\n. common-s"
}
]
About this extraction
This page contains the full source code of the pizzamig/pot GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 189 files (922.2 KB), approximately 311.3k tokens, and a symbol index with 1 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.