78 Commits
dev ... v2.0.3

Author SHA1 Message Date
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
7 changed files with 3505 additions and 1682 deletions

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

105
README.md
View File

@@ -1,4 +1,32 @@
## jaildk - a FreeBSD jail development kit
## jaildk - a FreeBSD jail development kit v2.0.0
## 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
used to build, update, manage and run jails in a versioned environment.
@@ -112,27 +140,30 @@ handy wrappers to make live easier.
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:
base -b <name> [-w] - build a new base
build <jail> <mode> [-b <base>] [-v <version>] - install a build chroot of a jail
base -b <name> [-w] [-s <script>] - build a new base
build <jail> -m <mode> [-b <base>] [-v <version>] - install a build chroot of a jail
create - create a new jail from a template
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:
install <jail> <mode> [-r function] - install a jail (prepare mounts, devfs etc)
(Un)installing Jails:
install <jail> -m <mode> [-r function] - install a jail (prepare mounts, devfs etc)
uninstall <jail> [-w] - uninstall a jail
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:
start <jail> - start a jail
stop <jail> - stop a jail
restart <jail> - restart a jail
status [<jail>] - display a jail's status
rc <jail> <mode> [-r <rc.d script>] - execute an rc-script inside a jail
status [<jail>] [-v] - display status of jails or <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:
login <jail> [<user>] - login into a jail
@@ -142,19 +173,39 @@ Transferring Jails:
freeze <jail> [-a -b -v <version>] - freeze (build an image of) a jail
thaw <image> - thaw (install) an image of a jail
Getting help:
Getting help and internals:
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
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,
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
@@ -321,7 +372,7 @@ mount - mount -t nullfs -o rw /jail/home/myjail/root-20201106 /jail/run/myjail/r
Jail myjail start:
Starting jails: myjail.
# jaildk startus myjail
# jaildk status myjail
Jail scipown status:
JID IP Address Hostname Path
myjail 172.16.1.1 myjail /jail/run/myjail
@@ -350,15 +401,16 @@ Next create a new base version:
```
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
```
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:
@@ -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
@@ -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
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:
`jaildk install myjail status -r pf`
`jaildk install myjail -m status -r pf`
You can of course manipulate the ruleset manually. `jaildk` installs
rulesets into a jail specific anchor using the following naming

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)

2549
src/jaildk.sh Executable file

File diff suppressed because it is too large Load Diff