96 Commits
dev ... main

Author SHA1 Message Date
T. von Dein
eabec94945 move to codeberg (#35) 2025-12-16 20:01:40 +01:00
b5efc90d29 fix #37: match jail name to id correctly 2025-04-06 15:16:50 +02:00
5cd15ebff6 fix #34: add documentation for pf rule generation 2025-04-01 12:55:25 +02:00
f278760c06 fix #36: forbid cloning to existing jail if name differs 2025-04-01 09:25:38 +02:00
fa4b9c08ef fix documentation issue #35: do not recommend invalid command line 2025-04-01 09:20:24 +02:00
T.v.Dein
5ca48c6d5c Add ci badge 2024-10-15 20:40:40 +02:00
T.v.Dein
6738e74167 Add -xe to CI run to see commands and exit immediately 2024-10-15 20:28:41 +02:00
40371fc507 fix base src tarball 2024-10-15 19:14:48 +02:00
b45bb280f9 manually build base, next try 2024-10-15 19:09:46 +02:00
26cc8b20d2 add sysrc call to enable jail 2024-10-15 18:48:48 +02:00
56a5f51585 install cpdup during prep 2024-10-15 18:45:56 +02:00
5470154a12 do really exit 1 2024-10-15 18:45:42 +02:00
10af21a48f another try, this time w/o make 2024-10-15 18:40:43 +02:00
d76f960e69 not using PATH 2024-10-15 18:32:40 +02:00
a00da3ffd4 fix yaml 2024-10-15 18:30:32 +02:00
54fb06fc7d added ci test runner 2024-10-15 18:22:47 +02:00
T.v.Dein
aee232054b Merge pull request #28 from Culsu/main
Fix for issue  #27
2024-10-15 08:26:28 +02:00
Culsu
f2dde50ffc fixed an error where jaildk status was trying to find a jail called v6, also fixed some column alignment when printing the status 2024-10-14 23:42:08 +02:00
8e893017be bump version 2024-10-06 16:22:32 +02:00
9fcf0beb9c fix #15: do not try to execute pf if there's no ip address configured 2024-10-06 16:20:11 +02:00
a293128eea fix #26: show correct usage after clone/create 2024-10-06 16:10:28 +02:00
27aada4b8e fix #24 (part II): always respond to -h with usage message 2024-10-06 16:08:19 +02:00
db33a41983 fix #24 (part I): get rid of perl, check for external programs 2024-10-06 16:04:45 +02:00
6fad6cd2f9 Merge branch 'main' of github.com:TLINDEN/jaildk 2024-09-18 10:31:42 +02:00
cafc20e743 implement #20: added -s parameter to base command to instal scripts 2024-09-18 10:30:55 +02:00
cf812919cb fix #19: bootstrap pkg when building a new base 2024-09-18 10:24:23 +02:00
e2aa249464 fix reinstall aboriting with jail -m doesnt exist 2024-09-18 10:21:44 +02:00
T.v.Dein
4dab8e10ea Merge pull request #22 from TLINDEN/develop
Fix ipfw call
2024-09-17 14:02:40 +02:00
Thomas von Dein
20f95781d9 fix makefile 2024-09-17 13:58:42 +02:00
ad1333ebb0 fix #21: only execute ipfw stuff if there's an ipfw.conf 2024-09-17 13:55:20 +02:00
T.v.Dein
514d0adeda Merge pull request #18 from Culsu/main
fixed an issue when trying to start a build-chroot with explicit base…
2024-06-26 18:13:06 +02:00
Culsu
22e02b7ce5 fixed an issue when trying to start a build-chroot with explicit base and version, fixed an issue with optargs indices 2024-06-26 12:05:02 +02:00
Thomas von Dein
2151ad6cc8 fix #16: call jaildk_start with -m interanally as well 2023-09-21 12:02:30 +02:00
Thomas von Dein
f43da7f0b0 finally fix https://github.com/adoyle-h/bash-completor/discussions/2 by just using the rc-scripts directly 2023-09-19 16:59:11 +02:00
Thomas von Dein
cbac202c38 sub completion still fails, revert 2023-09-18 18:15:56 +02:00
Thomas von Dein
0ce95ca7df try to fix rc -r 2023-09-18 18:11:21 +02:00
Thomas von Dein
7dded1c766 fix mode examples 2023-09-13 11:04:54 +02:00
Thomas von Dein
75cfd32c56 oh markdown, fuck off! 2023-09-13 10:58:09 +02:00
Thomas von Dein
36aa198eb8 Add information about breaking changes 2023-09-13 10:54:39 +02:00
Thomas von Dein
0541b99f5f Change -m params, bump version to 2.0.0, fix completion, reorg repo 2023-09-13 10:38:47 +02:00
Thomas von Dein
394e06e4f1 added completion support 2023-09-12 19:16:48 +02:00
Thomas von Dein
3de7933f97 added completion support 2023-09-12 19:15:45 +02:00
Thomas von Dein
e2c08a0235 fix-typo 2022-04-24 15:39:30 +02:00
Thomas von Dein
22adcd57c4 fixed vnet ipv6 interface config 2022-02-25 12:08:25 +01:00
Thomas von Dein
ad9ce1cfed fixed ipv6 pf rule generator 2022-02-22 19:14:41 +01:00
Thomas von Dein
768a051108 added prune command 2022-02-16 12:22:13 +01:00
Thomas von Dein
3437d7dce4 fixed mtree rc mode 2022-02-01 13:23:16 +01:00
Thomas von Dein
095819819e fixed mtree rc mode 2022-02-01 13:16:06 +01:00
Thomas von Dein
06baba0514 clone dir only if dst not empty 2021-07-18 19:49:30 +02:00
Thomas von Dein
60b8c0849a fix status base 2021-07-10 20:17:16 +02:00
Thomas von Dein
4c9667cdb6 fix v4 rdrs 2021-07-10 19:44:55 +02:00
Thomas von Dein
88b5f1c26b added syslog logging to ex() so that we always see wht jaildk did 2021-07-07 11:27:18 +02:00
Thomas von Dein
4d81b9c14b fixed pf ipv6 rule generation 2021-07-07 07:21:22 +02:00
Thomas von Dein
3c7fdf45db hm 2021-07-06 23:23:21 +02:00
Thomas von Dein
59967ab531 add auto_linklocal 2021-07-06 23:21:02 +02:00
Thomas von Dein
9409061e03 init 2021-07-06 21:51:20 +02:00
Thomas von Dein
426306457a fixed pf rdr, using ip w/o mask 2021-07-06 20:25:19 +02:00
Thomas von Dein
4d910f6d95 fixed pf multiple port feature 2021-07-06 20:12:27 +02:00
Thomas von Dein
0e99f015f3 forgot update -f check 2021-07-06 12:12:46 +02:00
Thomas von Dein
e3502c1258 added update command 2021-07-06 12:11:23 +02:00
Thomas von Dein
f4741dac5f fixed clone 2021-07-05 19:05:45 +02:00
Thomas von Dein
d53dc0549f fixed status output, didnt parse vnet jails w/o ip address correctly 2021-07-05 14:54:35 +02:00
Thomas von Dein
134076e74c fix typo 2021-07-05 14:37:17 +02:00
Thomas von Dein
938fc3a38b better status output 2021-07-05 14:35:24 +02:00
Thomas von Dein
3a3dce8903 Refactored:
- internal functions do not have the jaildk_ prefix anymore, this
  is now reserved for interactive commands only.
- added variable precedence using 'local' keyword to avoid variable
  conflicts etc.
- supress 'typoe' output
. use here-doc for vnet usage
2021-07-05 14:26:10 +02:00
Thomas von Dein
2d1e3ceef9 - simplified main switch statement
- status displays exposed ip of vnet jail
2021-07-04 20:46:52 +02:00
Thomas von Dein
6b4f80cf55 - (re) allow login :)
- added error checking to vnet command
2021-07-04 12:49:34 +02:00
Thomas von Dein
8c760ef130 added check if run as root 2021-07-04 12:27:17 +02:00
Thomas von Dein
10cb98bb57 fixed vnet ipv6 configuration, syntax error 2021-07-04 11:52:04 +02:00
Thomas von Dein
ca76632a2c changed vnet ipv6 setup, using routing not nat 2021-07-03 20:35:05 +02:00
Thomas von Dein
f1eefe2e41 fixed variuos pf generation bugs, now works at least 2021-07-03 16:32:19 +02:00
Thomas von Dein
830ca86afe only generate pf ruleset if in start or restart mode 2021-07-02 19:46:56 +02:00
Thomas von Dein
7e5c2ad591 added pf rule generator 2021-07-02 13:03:33 +02:00
Thomas von Dein
a9fb600f4b added vnet support, enhanced status command 2021-06-30 15:15:28 +02:00
Thomas von Dein
2f44630168 #13 - changed default to no (do not delete old dist files) 2021-06-28 07:34:08 +02:00
Thomas von Dein
5451130343 clean up dist dir before building a new base (fixes #13) 2021-06-26 20:31:02 +02:00
Thomas von Dein
4e2760b854 added unionfs support 2021-06-25 07:52:03 +02:00
Thomas von Dein
5de4bf1172 added uninstall -a option to remove everything and fixed -w again 2021-01-28 20:18:35 +01:00
Thomas von Dein
cee8aa66ef Fixed build/run uninstall w/ unintialised variable 2021-01-28 20:00:33 +01:00
T.v.Dein
b721acd23d Merge pull request #12 from Culsu/main
Some convenience stuff
2021-01-27 19:40:20 +01:00
Culsu
0b32f9e34b Added a NO_BOLD option to disable bold text manually, also suppressed some error messages by rcorder and ls if local-etc/rc.d is not present inside the jail 2021-01-25 00:22:54 +01:00
Thomas von Dein
f0a325ee53 fixed login() 2021-01-14 13:10:09 +01:00
Thomas von Dein
b02d2d6c42 disabled rcoff feature, doesnt work as expected 2021-01-04 12:20:57 +01:00
Thomas von Dein
9bfa539e02 fixed rc function: only call rc-script specified with -r 2020-12-19 17:34:53 +01:00
Thomas von Dein
c374abf6fa added pf restart 2020-12-17 20:07:12 +01:00
Thomas von Dein
32455bb1ee added -v and -b to reinstall command 2020-12-14 20:18:20 +01:00
Thomas von Dein
569cc6bb6d fixed clone function 2020-12-14 15:26:32 +01:00
Thomas von Dein
ee34a551b5 same with base 2020-12-13 14:58:54 +01:00
Thomas von Dein
906c59aee8 fix version conflict 2020-12-13 14:54:16 +01:00
Thomas von Dein
6bcdb1ac20 version 2020-12-13 14:49:39 +01:00
Thomas von Dein
25d207daf7 _ fix 2020-12-13 14:45:08 +01:00
Thomas von Dein
26b000dff5 do not fiddle w/ networking on build chroot's 2020-12-13 14:43:18 +01:00
Thomas von Dein
914d4c24f8 fetch => fetchports (more clarity) 2020-12-13 14:37:20 +01:00
Thomas von Dein
643c10d777 catch invalid usage 2020-12-13 14:24:14 +01:00
Thomas von Dein
2f38a0c7d8 fixed "jaildk status' (w/o jail) and jaildk_rc all 2020-12-13 14:17:13 +01:00
Thomas von Dein
9a420006c5 Merge branch 'dev' into main 2020-12-04 20:35:11 +01:00
9 changed files with 3617 additions and 1684 deletions

16
.github/assets/jail.conf vendored Normal file
View File

@@ -0,0 +1,16 @@
* {
exec.start = "/bin/sh /etc/rc";
exec.stop = "/bin/sh /etc/rc.shutdown";
allow.raw_sockets = "false";
sysvmsg = "new";
sysvsem = "new";
sysvshm = "new";
host.hostname = $name;
path = "/jail/run/$name";
exec.prestart = "/jail/bin/jaildk install $name start";
exec.clean = "true";
}
test {
ip4.addr = "172.16.0.1";
}

52
.github/workflows/ci.yaml vendored Normal file
View File

@@ -0,0 +1,52 @@
name: Test-Jaildk
on: [push]
jobs:
test:
runs-on: ubuntu-latest
name: Test jaildk on FreeBSD
steps:
- name: checkout
uses: actions/checkout@v4
- name: Test in FreeBSD
uses: vmactions/freebsd-vm@v1
id: testjaildk
with:
release: "14.1"
usesh: true
prepare: |
pkg install -y curl cpdup
run: |
freebsd-version
sysctl hw.model
sysctl hw.ncpu
sysctl hw.physmem
sysctl hw.usermem
ls -la
ifconfig em0 172.16.0.1/32 alias
ifconfig -a
set -x -e
sysrc jail_enable="YES"
cp .github/assets/jail.conf /etc/
cp src/jaildk.sh jaildk
sh jaildk setup /jail
fetch https://download.freebsd.org/ftp/releases/amd64/amd64/14.1-RELEASE/base.txz -o /jail/base/14.1-RELEASE-base.txz
mkdir -p /jail/base/14.1-RELEASE
tar -xf /jail/base/14.1-RELEASE-base.txz -C /jail/base/14.1-RELEASE --unlink
/jail/bin/jaildk create test
ls -l /jail/etc/test
/jail/bin/jaildk build test -m start
df -h /jail/build/test/etc
echo 'sshd_enable="Yes"' > /jail/build/test/usr/local/etc/rc.conf
chroot /jail/build/test /etc/rc.d/sshd keygen
/jail/bin/jaildk start test
/jail/bin/jaildk status | grep -E "test|Jail"

14
Makefile Normal file
View File

@@ -0,0 +1,14 @@
JAILDIR=/jail
all:
bash bin/bash-completor -c src/completions.sh
grep -B10 COMPLETIONCODE src/jaildk.sh | grep -v COMPLETIONCODE > jaildk
cat src/_jaildk-completion.bash >> jaildk
grep -A 10000 COMPLETIONCODE src/jaildk.sh | grep -v COMPLETIONCODE >> jaildk
rm -f src/_jaildk-completion.bash
install:
sh jaildk setup $(JAILDIR)
clean:
rm -f jaildk

172
README.md
View File

@@ -1,4 +1,32 @@
## jaildk - a FreeBSD jail development kit ## jaildk - a FreeBSD jail development kit v2.0.4
## Breaking Changes
It is not possible to upgrade an existing installation of jaildk using
the builtin `jaildk update` from version 1.x to 2.x!
So, in order to upgrade to the next major version, check out the repo and execute:
```
make
make install JAILDIR=/your/jaildir
```
See below for more details. Starting with 2.0.0 `jaildk update` can be used again.
In addition starting with 2.0.0 the commandlines of the following subcommands changed:
| 1.x | 2.0.0 up |
|---------------------------------------------------------|------------------------------------------------------------|
| `jaildk build <jail> <mode> [-b <base>] [-v <version>]` | `jaildk build <jail> -m <mode> [-b <base>] [-v <version>]` |
| `jaildk install <jail> <mode> [-r function]` | `jaildk install <jail> -m <mode> [-r function]` |
| `rc <jail> <mode> [-r <rc.d script>]` | `rc <jail> -m <mode> [-r <rc.d script>]` |
| `ipfw <jail> <mode>` | `ipfw <jail> -m <mode>` |
So, every subcommand supporting a mode parameter needs that parameter
now specified as an argument to the `-m` parameter.
## Introduction
This is the README for the FreeBSD jail utility `jaildk`. It can be This is the README for the FreeBSD jail utility `jaildk`. It can be
used to build, update, manage and run jails in a versioned environment. used to build, update, manage and run jails in a versioned environment.
@@ -112,49 +140,72 @@ handy wrappers to make live easier.
For an overview of the provided commands, here's the usage screen: For an overview of the provided commands, here's the usage screen:
``` ```
Usage: /usr/local/bin/jaildk <command> <mode-args> Usage: ./jaildk <command> <command-args>
Building Jails: Building Jails:
base -b <name> [-w] - build a new base base -b <name> [-w] [-s <script>] - build a new base
build <jail> <mode> [-b <base>] [-v <version>] - install a build chroot of a jail build <jail> -m <mode> [-b <base>] [-v <version>] - install a build chroot of a jail
create - create a new jail from a template create - create a new jail from a template
clone -s <src> -d <dst> [-o <v>] [-n <v>] - clone an existing jail or jail version clone -s <src> -d <dst> [-o <v>] [-n <v>] - clone an existing jail or jail version
fetch - fetch current port collection fetchports [-v <version>] - fetch current port collection
Installing Jails: (Un)installing Jails:
install <jail> <mode> [-r function] - install a jail (prepare mounts, devfs etc) install <jail> -m <mode> [-r function] - install a jail (prepare mounts, devfs etc)
uninstall <jail> [-w] - uninstall a jail uninstall <jail> [-w] - uninstall a jail
remove <jail> - remove a jail or a jail version remove <jail> - remove a jail or a jail version
reinstall <jail> - stop, remove, install and start a jail reinstall <jail> [-b <base>] [-v <version>] - stop, remove, install and start a jail, if
-b and/or -v is set, update the jail config
prune [-b | -a | -j <jail> - display unused directories
Maintaining Jails: Maintaining Jails:
start <jail> - start a jail start <jail> - start a jail
stop <jail> - stop a jail stop <jail> - stop a jail
restart <jail> - restart a jail restart <jail> - restart a jail
status [<jail>] - display a jail's status status [<jail>] [-v] - display status of jails or <jail>
rc <jail> <mode> [-r <rc.d script>] - execute an rc-script inside a jail rc <jail> -m <mode> [-r <rc.d script>] - execute an rc-script inside a jail
ipfw <jail> -m <mode> - add or remove ipfw rules
Managing Jails: Managing Jails:
login <jail> [<user>] - login into a jail login <jail> [<user>] - login into a jail
blogin <jail> - chroot into a build jail blogin <jail> - chroot into a build jail
Transferring Jails: Transferring Jails:
freeze <jail> [-a -b -v <version>] - freeze (build an image of) a jail freeze <jail> [-a -b -v <version>] - freeze (build an image of) a jail
thaw <image> - thaw (install) an image of a jail thaw <image> - thaw (install) an image of a jail
Getting help: Getting help and internals:
help <command> - request help on <command> completion - print completion code. to use execute in a bash:
source <(jaildk completion)
help <command> - request help on <command>
version - print program version
update [-f] - update jaildk from git repository
``` ```
## Installation ## Installation
Download the file `jaildk` or clone this repository to your FreeBSD server and execute the following command: Clone this repository to your FreeBSD server and execute the following command:
``` ```
./jaildk setup <directory> make
make install
``` ```
This will create the directory structure required for the tool itself, This will create the directory structure required for the tool itself,
create a template jail and build a base directory. create a template jail and build a base directory. The default base
directory is `/jail`. You can modify this by issuing:
```
make install JAILDIR=/another/dir
```
Be aware, that the `jaildk` script itself will only be installed to
`$JAILDIR/bin/jaildk`. Either put this directory into your `$PATH`
variable or create a symlink to the script in some bin dir.
## Bash Completion
If you want to use `jaildk` with bash completion, put this line into your `.bashrc`:
```
source <(jaildk completion)
```
## Basic usage ## Basic usage
@@ -321,7 +372,7 @@ mount - mount -t nullfs -o rw /jail/home/myjail/root-20201106 /jail/run/myjail/r
Jail myjail start: Jail myjail start:
Starting jails: myjail. Starting jails: myjail.
# jaildk startus myjail # jaildk status myjail
Jail scipown status: Jail scipown status:
JID IP Address Hostname Path JID IP Address Hostname Path
myjail 172.16.1.1 myjail /jail/run/myjail myjail 172.16.1.1 myjail /jail/run/myjail
@@ -350,15 +401,16 @@ Next create a new base version:
``` ```
jaildk base -b `uname -r` jaildk base -b `uname -r`
``` ```
But of course you can update a jail with the current base as well.
Now you can create clone of your jail with a new version: Now you can clone of your jail with a new version:
``` ```
jaildk clone -s myjail -d myjail -o 20201106 -n 20210422 jaildk clone -s myjail -d myjail -o 20201106 -n 20210422
``` ```
Mount the build chroot for the new version: Mount the build chroot for the new version:
``` ```
jaildk build myjail start -b `uname -r` -v 20210422 jaildk build myjail -m start -b `uname -r` -v 20210422
``` ```
And finally chroot into the new jail and update it: And finally chroot into the new jail and update it:
@@ -368,9 +420,20 @@ pkg update
... ...
``` ```
The last step is to remove the current running jail, change the version in `etc/myjail.conf`, install and start the new version. The last step is to remove the current running jail, change the
version in `etc/myjail.conf`, install and start the new version. This
can be easily done with the following command:
```
jaildk reinstall myjail -b `uname -r` -v 20210422
```
If there's anything wrong you can always go back to the previous version using the above steps. This command also creates a copy of the current jail.conf.
If there's anything wrong you can always go back to the previous
version using the following command (using the previous base and version):
```
jaildk reinstall myjail -b 12.2-RELEASE-p1 -v 20201106
```
## Advanced Features ## Advanced Features
@@ -529,11 +592,11 @@ pass in quick inet6 proto tcp from any to $ip6 port $prodports keep state
That's it already. Now install the jail as usual. You can also install That's it already. Now install the jail as usual. You can also install
the pf ruleset for the jail separately: the pf ruleset for the jail separately:
`jaildk install myjail start -r pf` `jaildk install myjail -m start -r pf`
To take look at the rules, execute: To take look at the rules, execute:
`jaildk install myjail status -r pf` `jaildk install myjail -m status -r pf`
You can of course manipulate the ruleset manually. `jaildk` installs You can of course manipulate the ruleset manually. `jaildk` installs
rulesets into a jail specific anchor using the following naming rulesets into a jail specific anchor using the following naming
@@ -545,6 +608,45 @@ Manipulate a jail specific table:
`pfctl -a /jail/myjail -t blocked -T show` `pfctl -a /jail/myjail -t blocked -T show`
## Generating pf rule sets
It is also possible to let jaildk generate the pf rule sets from the
jail config. You can generate `map`s and `rule`s. Maps will be used
for mapping ipv4 connections and rules primarily for ipv6.
A map is defined by a name. You can define many maps. Example:
```toml
map_prom_exposed_port="9100"
map_prom_exposed_ip="172.16.1.1"
map_prom_allow_from="10.2.3.4" # optional, default: any allowed
```
Then you reference the maps like this:
```toml
maps="prom web git"
```
You can also specify the ip address used to connect to the outside:
```toml
masq_ip="172.16.1.1"
```
Rules are being used for incoming ipv6 traffic, which is being routed
only. The semtantics are the same:
```toml
rules="web git"
rule_web_proto="tcp"
rule_web_port="{80,443}"
rule_git_proto="tcp"
rule_git_port="22"
```
## Getting help ## Getting help
Although I'm happy to hear from jaildk users in private email, Although I'm happy to hear from jaildk users in private email,
@@ -552,7 +654,7 @@ that's the best way for me to forget to do something.
In order to report a bug, unexpected behavior, feature requests In order to report a bug, unexpected behavior, feature requests
or to submit a patch, please open an issue on github: or to submit a patch, please open an issue on github:
https://github.com/TLINDEN/jaildk/issues. https://codeberg.org/scip/jaildk/issues.
## Copyright and license ## Copyright and license
@@ -566,5 +668,5 @@ F.Sass (Culsu)
## Project homepage ## Project homepage
https://github.com/TLINDEN/jaildk https://codeberg.org/scip/jaildk

4
TODO Normal file
View File

@@ -0,0 +1,4 @@
- vnet ipv6 doesnt work anymore
UPDATE: with auto_linklocal seems to work after some seconds
- on reboot, no pf will be started
- v6 addr on bridge in rc.conf is not applied on reboot

734
bin/bash-completor Executable file
View File

@@ -0,0 +1,734 @@
#!/usr/bin/env bash
set -o errexit
set -o nounset
set -o pipefail
set -o errtrace
(shopt -p inherit_errexit &>/dev/null) && shopt -s inherit_errexit
readonly VERSION=v0.1.0
readonly ARGS=$*
readonly SPACES_8=' '
readonly SPACES_6=' '
readonly SPACES_4=' '
readonly SPACES_2=' '
declare -r RED="\\e[31m"
declare -r GREEN="\\e[32m"
declare -r YELLOW="\\e[33m"
declare -r CYAN="\\e[36m"
declare -r RESET_ALL="\\e[0m"
debug() {
printf "%b[Debug] %s%b\n" "$CYAN" "$*" "$RESET_ALL" >/dev/tty
}
warn() {
printf "%b[Warn] %s%b\n" "$YELLOW" "$*" "$RESET_ALL" >/dev/tty
}
error() {
printf "%b[Error] %s%b\n" "$RED" "$*" "$RESET_ALL" >/dev/tty
}
suggest() {
printf "%b[Suggest] %s%b\n" "$GREEN" "$*" "$RESET_ALL" >/dev/tty
}
# Copy from https://github.com/adoyle-h/lobash/blob/develop/src/modules/is_array.bash
is_array() {
local attrs
# shellcheck disable=2207
attrs=$(declare -p "$1" 2>/dev/null | sed -E "s/^declare -([-a-zA-Z]+) .+/\\1/" || true)
# a: array
# A: associate array
if [[ ${attrs} =~ a|A ]]; then return 0; else return 1; fi
}
is_func() {
declare -F "$1" &>/dev/null
}
get_varname() {
local name=${1:-}
local encoded=${word_to_varname[$name]:-}
if [[ -z ${encoded} ]]; then
encoded=${name//[^a-zA-Z_]/_}
fi
echo "${encoded}"
}
is_gnu_sed() {
local out
out=$(${1:-sed} --version 2>/dev/null)
[[ $out =~ 'GNU sed' ]]
}
reply_words() {
local IFS=$'\n'
# shellcheck disable=2207
COMPREPLY=( $(IFS=', ' compgen -W "$*" -- "${cur#=}") )
}
reply_list() {
local IFS=', '
local array_list="" array_name
# shellcheck disable=2068
for array_name in $@; do
array_list="$array_list \${${array_name}[*]}"
done
array_list="${array_list[*]:1}"
IFS=$'\n'' '
eval "COMPREPLY=( \$(compgen -W \"$array_list\" -- \"\$cur\") )"
}
reply_files() {
local IFS=$'\n'
compopt -o nospace -o filenames
# shellcheck disable=2207
COMPREPLY=( $(compgen -A file -- "$cur") )
}
reply_files_in_pattern() {
compopt -o nospace -o filenames
local path
while read -r path; do
if [[ $path =~ $1 ]] || [[ -d $path ]]; then
COMPREPLY+=( "$path" )
fi
done < <(compgen -A file -- "$cur")
}
reply_dirs() {
local IFS=$'\n'
compopt -o nospace -o filenames
# shellcheck disable=2207
COMPREPLY=( $(compgen -A directory -- "$cur") )
}
make_get_varnames() {
echo ""
declare -p word_to_varname | sed -e "s/word_to_varname/_${cmd}_comp_word_to_varname/"
declare -f get_varname | sed -e "s/get_varname/_${cmd}_comp_util_get_varname/" -e 's/ *$//g' \
-e "s/word_to_varname/_${cmd}_comp_word_to_varname/"
}
make_dumped_variables() {
echo ""
local name
for name in $(compgen -A variable var_); do
declare -p "$name" | sed "s/^declare -.* var_/_${cmd}_comp_var_/"
done
}
make_header() {
cat <<EOF
# This file is generated by [bash-completor](https://github.com/adoyle-h/bash-completor/tree/$VERSION). Do not modify it manually.
#
# [Usage]
# Put "source $output" in your bashrc.
#
# If you want to debug the completion.
# Search '# Uncomment this line for debug' line in this file.
#
# [Update Script]
# bash-completor $ARGS
EOF
if [[ -n ${version:-} ]]; then
cat <<EOF
#
# [Version] $version
EOF
fi
if [[ -n ${license:-} ]]; then
cat <<EOF
#
# [License] $license
EOF
fi
if (( ${#authors[@]} > 0 )); then
cat <<EOF
#
# [Authors]
EOF
{
local IFS=$'\n'
local author
for author in "${authors[@]}"; do
echo "# ${author}"
done
}
fi
if (( ${#maintainers[@]} > 0 )); then
cat <<EOF
#
# [Maintainers]
EOF
{
local IFS=$'\n'
local maintainer
for maintainer in "${maintainers[@]}"; do
echo "# ${maintainer}"
done
}
fi
if [[ -n ${description:-} ]]; then
cat <<EOF
#
# [Description]
# ${description}
EOF
fi
if [[ -n ${notice:-} ]]; then
cat <<EOF
#
# [Notice]
# ${notice}
EOF
fi
cat <<EOF
# shellcheck disable=2207
# editorconfig-checker-disable
EOF
}
make_opts_variable() {
local opts_varname=$1
local -n opts=$opts_varname
printf '\n_%s_comp_%s=( ' "$cmd" "$opts_varname"
for opt in "${opts[@]}"; do
printf '%s ' "${opt/:*/}"
done
printf ')\n'
}
parse_action() {
local var=$1
local position=$2
if [[ ${var:0:1} == '@' ]]; then
case $var in
@hold)
printf ''
;;
*)
local func_name=${var:1}
func_name=${func_name/:*/}
if [[ ${map_reply_funcs["reply_${func_name}"]:-} == true ]]; then
local func_arg=${var/@${func_name}:/}
if (( ${#func_arg} > 0 )) && [[ ${func_arg[*]:0:1} != '@' ]]; then
printf -- "_%s_comp_reply_%s '%s'" "$cmd" "$func_name" "$func_arg"
else
printf -- '_%s_comp_reply_%s' "$cmd" "$func_name"
fi
else
error "Invalid '$position': The action '$var' is not defined."
case $var in
@f*) suggest "Try '@files' instead of '$var'." ;;
@d*) suggest "Try '@dirs' instead of '$var'." ;;
@h*) suggest "Try '@hold' instead of '$var'." ;;
*) suggest "Try '@files', '@dirs', '@hold' or other reply functions. See https://github.com/adoyle-h/bash-completor/docs/syntax.md#reply-functions "
esac
exit 5
fi
;;
esac
else
if [[ -n "$var" ]]; then
printf -- "_%s_comp_reply_words '%s'" "$cmd" "$var"
else
printf ''
fi
fi
}
make_reply_action() {
local varname=$1
local -n var=$varname
local reply
if [[ -v "$varname" ]]; then
reply=$(parse_action "$var" "$varname=$var")
elif is_array "$varname"; then
reply="_${cmd}_comp_reply_list '${var}'"
else
reply="_${cmd}_comp_reply_files"
fi
echo "$reply"
}
make_reply_set() {
cat <<EOF
_${cmd}_comp_reply_set() {
local IFS=', '
local array_list="" array_name
# shellcheck disable=2068
for array_name in \$@; do
array_list="\$array_list \\\${_${cmd}_comp_var_\${array_name}[*]}"
done
array_list="\${array_list[*]:1}"
IFS=\$'\n'' '
eval "COMPREPLY=( \\\$(compgen -W \"\$array_list\" -- \"\\\$cur\") )"
}
EOF
map_reply_funcs[reply_set]=true
}
if is_gnu_sed; then
# For GNU sed
sed_reply_utils() {
declare -f "$name" | sed -e "s/reply_/_${cmd}_comp_reply_/g" -e 's/ *$//g' |\
sed -e ":a;N;\$!ba;s/IFS='\n'/IFS=\$'\\\\n'/g"
}
else
# For BSD sed
sed_reply_utils() {
declare -f "$name" | sed -e "s/reply_/_${cmd}_comp_reply_/g" -e 's/ *$//g' |\
sed -e ':a' -e 'N' -e '$!ba' -e "s/IFS='\n'/IFS=\$'\\\\n'/g"
}
fi
make_reply_utils() {
local name
map_reply_funcs[reply_hold]=true
# Make framework and developer defined reply functions
for name in $(compgen -A function reply_); do
echo ""
sed_reply_utils
map_reply_funcs[$name]=true
done
make_reply_set
# Make developer custom reply functions
for name in $(compgen -A variable reply_); do
local -n list="$name"
local func_name=${list[0]}
if is_func "$func_name"; then
local rest=()
local str
for str in "${list[@]:1}"; do
rest+=("'$str'")
done
cat <<EOF
_${cmd}_comp_${name}() {
_${cmd}_comp_${func_name} ${rest[@]}
}
EOF
else
error "Not found function '$func_name' for config '$name'"
exit 7
fi
map_reply_funcs[$name]=true
done
}
_make_cmd_option() {
local opt=$1
local indent=$2
local default_action=$3
if [[ $opt =~ : ]]; then
local option=${opt/:*/}
local var=${opt/${option}:/}
else
local option=$opt
local var=''
fi
if [[ ${option: -1} == '=' ]]; then
# skip --option=
return 0
fi
if [[ $option == "$opt" ]]; then
# skip --option without :
return 0
fi
local action
action=$(parse_action "$var" "$opt")
# Skip to print case condition. Because this condition action is same to default_action.
# default_action means "*) $default_action ;;"
if [[ "$action" != "$default_action" ]]; then
printf -- '%s) %s ;;\n' "$indent$option" "$action"
fi
}
_make_cmd_options() {
echo " # rely the value of command option"
local opt
for opt in "${opts[@]}"; do
_make_cmd_option "$opt" "$SPACES_6" "$reply_opts_fallback"
done
}
_make_equal_sign_option() {
local opt=$1
local indent="$SPACES_4"
if [[ $opt =~ : ]]; then
local option=${opt/:*/}
local var=${opt/${option}:/}
else
local option=$opt
local var=''
fi
if [[ $option =~ =$ ]]; then
local action
action=$(parse_action "$var" "$opt")
printf -- '%s) %s ;;\n' "$indent$option" "$action"
else
if [[ $option =~ =[@-_a-zA-Z] ]]; then
local recommend=${option/=/=:}
recommend=${recommend// /,} # developer may use space delimiter
warn "The option '$option' maybe missing the ':'. Do you need '${recommend}'?"
fi
fi
}
_make_equal_sign_options() {
for opt in "${opts[@]}"; do
_make_equal_sign_option "$opt"
done
}
make_equal_sign_opts_func() {
local opts_varname=$1
local -n opts=$opts_varname
local equal_sign_options
equal_sign_options=$(_make_equal_sign_options)
if [[ -n $equal_sign_options ]]; then
cat <<EOF
_${cmd}_comp_equal_sign_${opts_varname}() {
case "\${1}=" in
$equal_sign_options
esac
}
EOF
map_equal_signs[${opts_varname}]=true
fi
}
make_cmd_core() {
local opts_varname=$1
local reply_args=$2
local reply_opts_fallback=$3
local -n opts=$opts_varname
if [[ " ${opts[*]} " == *' -- '* ]]; then
cat <<EOF
if [[ \$COMP_LINE == *' -- '* ]]; then
# When current command line contains the "--" option, other options are forbidden.
${reply_args}
elif [[ \${cur:0:1} == [-+] ]]; then
EOF
else
cat <<EOF
if [[ \${cur:0:1} == [-+] ]]; then
EOF
fi
cat <<EOF
# rely options of command
_${cmd}_comp_reply_list _${cmd}_comp_${opts_varname}
EOF
if [[ "${opts[*]}" =~ = ]]; then
# The options contain equal_sign
cat <<EOF
if [[ \${COMPREPLY[*]} =~ =\$ ]]; then compopt -o nospace; fi
EOF
fi
if [[ -n ${map_equal_signs[${opts_varname}]:-} ]]; then
cat <<EOF
elif [[ \${cur} == = ]]; then
_${cmd}_comp_equal_sign_${opts_varname} "\$prev"
EOF
fi
cat <<EOF
elif [[ \${prev:0:1} == [-+] ]]; then
case "\${prev}" in
$(_make_cmd_options)
*) $reply_opts_fallback ;;
esac
EOF
if [[ -n ${map_equal_signs[${opts_varname}]:-} ]]; then
cat <<EOF
elif [[ \${prev} == = ]]; then
_${cmd}_comp_equal_sign_${opts_varname} "\${COMP_WORDS[\$(( COMP_CWORD - 2 ))]}"
EOF
fi
cat <<EOF
else
# rely the argument of command
$reply_args
fi
EOF
}
make_subcmd_opts() {
local subcmd_opts
for subcmd_opts in $(compgen -A variable subcmd_opts_); do
make_opts_variable "$subcmd_opts"
done
}
make_subcmds() {
cat <<EOF
_${cmd}_comp_subcmds=( ${subcmds[*]} )
EOF
}
make_subcmd_completion() {
local subcmd_varname=$1
local reply_args
if [[ -v "subcmd_args_${subcmd_varname}" ]]; then
reply_args=$(make_reply_action "subcmd_args_${subcmd_varname}")
else
reply_args=$(make_reply_action subcmd_args__fallback)
fi
local reply_opts_fallback
if [[ -v "subcmd_opts_${subcmd_varname}_fallback" ]]; then
reply_opts_fallback=$(make_reply_action "subcmd_opts_${subcmd_varname}_fallback")
else
reply_opts_fallback=$reply_args
fi
cat <<EOF
_${cmd}_completions_$subcmd_varname() {
$(make_cmd_core "subcmd_opts_${subcmd_varname}" "$reply_args" "$reply_opts_fallback")
}
EOF
}
make_subcmd_alias_completion() {
local src
for src in "${!subcmd_comp_alias[@]}"; do
printf '_%s_completions_%s() { _%s_completions_%s; }\n' \
"$cmd" "$(get_varname "$src")" "$cmd" "$(get_varname "${subcmd_comp_alias[$src]}")"
done
}
make_subcmd_completions() {
local subcmd subcmd_varname
for subcmd in "${subcmds[@]}"; do
subcmd_varname=$(get_varname "$subcmd")
if is_array "subcmd_opts_${subcmd_varname}"; then
make_equal_sign_opts_func "subcmd_opts_${subcmd_varname}"
make_subcmd_completion "$subcmd_varname"
fi
done
make_subcmd_alias_completion
make_subcmd_completion _fallback
}
make_main_completion() {
make_equal_sign_opts_func "cmd_opts"
cat <<EOF
_${cmd}_completions() {
COMPREPLY=()
local cur=\${COMP_WORDS[COMP_CWORD]}
local prev=\${COMP_WORDS[COMP_CWORD-1]}
# Uncomment this line for debug
# echo "[COMP_CWORD:\$COMP_CWORD][cur:\$cur][prev:\$prev][WORD_COUNT:\${#COMP_WORDS[*]}][COMP_WORDS:\${COMP_WORDS[*]}]" >> bash-debug.log
EOF
local reply_args
if $has_subcmds; then
cat <<EOF
if (( COMP_CWORD > 1 )); then
# Enter the subcmd completion
local subcmd_varname
subcmd_varname="\$(_${cmd}_comp_util_get_varname "\${COMP_WORDS[1]}")"
if type "_${cmd}_completions_\$subcmd_varname" &>/dev/null; then
"_${cmd}_completions_\$subcmd_varname"
else
# If subcmd completion function not defined, use the fallback
"_${cmd}_completions__fallback"
fi
return 0
fi
EOF
reply_args="_${cmd}_comp_reply_list _${cmd}_comp_subcmds"
else
reply_args=$(make_reply_action cmd_args)
fi
local reply_opts_fallback
if [[ -v cmd_opts_fallback ]]; then
reply_opts_fallback=$(make_reply_action cmd_opts_fallback)
else
reply_opts_fallback=$(make_reply_action cmd_args)
fi
cat <<EOF
# Enter the cmd completion
$(make_cmd_core "cmd_opts" "$reply_args" "$reply_opts_fallback")
}
complete -F _${cmd}_completions -o bashdefault ${cmd_name}
# vi: sw=2 ts=2
EOF
}
make() {
make_header
make_opts_variable cmd_opts
make_dumped_variables
if $has_subcmds; then
make_subcmd_opts
make_get_varnames
fi
make_reply_utils
if $has_subcmds; then
make_subcmds
make_subcmd_completions
fi
make_main_completion
}
do_make() {
# NOTE: Naming variable should avoid some prefixes like "reply_" and "subcmd_opts_". Search "compgen -A".
local conf_path=$1
local has_subcmds=false
local equal_sign_idx=0
local -A map_reply_funcs=() map_equal_signs=()
local output cmd cmd_name cmd_args notice
local -a authors=() maintainers=() subcmds=() cmd_opts=()
local -A subcmd_comp_alias=() word_to_varname=()
check_conf "$conf_path"
local output_path
output_path="$(dirname "$conf_path")/$output"
make > "$output_path"
printf '%bGenerated file: %s%b\n' "${GREEN}" "$output_path" "$RESET_ALL"
}
usage() {
cat <<EOF
Usage: bash-completor [options]
Options:
-c <config_path> To generate Bash completion script based on configuration
-h|--help Print the usage
--version Print the version of bash-completor
Description: Quickly generate Bash completion script based on configuration.
Config Syntax: https://github.com/adoyle-h/bash-completor/docs/syntax.md
Project: https://github.com/adoyle-h/bash-completor
Version: $VERSION
EOF
}
check_conf() {
local conf_path=$1
if [[ ! -f $conf_path ]]; then
echo "Not found config file at $conf_path" >&2
exit 3
fi
# shellcheck disable=1090
. "$conf_path"
# Set default values of config options
cmd_name=$cmd
cmd=$(get_varname "$cmd_name")
cmd_args=${cmd_args:-@files}
subcmd_args__fallback=${subcmd_args__fallback:-@files}
if (( ${#subcmds[@]} > 0 )); then
has_subcmds=true
fi
}
main() {
if (( $# == 0 )); then usage; exit 0; fi
case "$1" in
-c)
do_make "$2"
;;
-h|--help)
usage
;;
--version)
echo "$VERSION"
;;
*)
echo "Invalid option '$1'." >&2
exit 2
;;
esac
}
main "$@"

1649
jaildk

File diff suppressed because it is too large Load Diff

108
src/completions.sh Normal file
View File

@@ -0,0 +1,108 @@
output=_jaildk-completion.bash
cmd=jaildk
cmd_opts=()
subcmds=(base build create clone fetchports install uninstall remove
reinstall prune start stop restart status rc ipfw login
blogin freeze thaw help version update)
reply_jail() {
local jails=$(ls $JAILDIR/etc)
COMPREPLY=( $(compgen -W "${jails[*]}" -- "$cur") )
}
reply_base() {
local bases=$(ls $JAILDIR/base)
COMPREPLY=( $(compgen -W "${bases[*]}" -- "$cur") )
}
reply_version() {
local versions=$(ls -d $JAILDIR/etc/*/etc-*|cut -d- -f2 | sort -u)
COMPREPLY=( $(compgen -W "${versions[*]}" -- "$cur") )
}
# we're taking the easy path here. There might be cases where the
# $name_enable variable doesn't match the actual rc-Script, which
# we will not catch the way we're doing it here, but these are rare
# and the user can specify something manually as well. Also this
# method is way faster than executing rcorder inside the jail
reply_rcscripts() {
local jail=${COMP_WORDS[2]}
local scripts=$(ls $JAILDIR/run/$jail/usr/local/etc/rc.d)
COMPREPLY=( $(compgen -W "${scripts[*]}" -- "$cur") )
}
functions='mount,ports,mtree,pf'
modes='start,stop,status,restart'
### sub cmd base
subcmd_opts_base=(-b -w)
### sub cmd build
subcmd_opts_build=(-b:@base -v:@version -m:$modes)
subcmd_args_build=@jail
### sub cmd clone
subcmd_opts_clone=(-s:@jail -d:@jail -o:@version -n:@version)
### sub cmd fetchports
subcmd_opts_fetchports=(-v:@version)
### sub cmd install
subcmd_opts_install=(-m:$modes -r:$functions)
subcmd_args_install=@jail
### sub cmd uninstall
subcmd_opts_uninstall=(-w)
subcmd_args_uninstall=@jail
### sub cmd remove
subcmd_args_remove=@jail
### sub cmd reinstall
subcmd_opts_reinstall=(-b:@base -v:@version)
subcmd_args_reinstall=@jail
### sub cmd prune
subcmd_opts_prune=(-b -a -j:@jail)
### sub cmd start
subcmd_args_start=@jail
### sub cmd stop
subcmd_args_stop=@jail
### sub cmd restart
subcmd_args_restart=@jail
### sub cmd status
subcmd_opts_status=(-v)
subcmd_args_status=@jail
### sub cmd rc
subcmd_opts_rc=(-m:$modes -r:@rcscripts)
subcmd_args_rc=@jail
### sub cmd ipfw
subcmd_opts_ipfw=(-m:$modes)
subcmd_args_ipfw=@jail
### sub cmd login
subcmd_args_login=@jail
### sub cmd blogin
subcmd_args_blogin=@jail
### sub cmd freeze
subcmd_opts_freeze=(-a -b -v:@version)
subcmd_args_freeze=@jail
### sub cmd thaw
subcmd_args_thaw=@files
### sub cmd help
subcmd_args_help="${subcmds[*]}"
### sub cmd update
subcmd_opts_update=(-f)

2552
src/jaildk.sh Executable file

File diff suppressed because it is too large Load Diff