2 Commits
v2.0.3 ... dev

Author SHA1 Message Date
Thomas von Dein
d43d565ec9 experimanetal, unfinished 2020-12-13 14:08:45 +01:00
Thomas von Dein
30c715e2d3 experimental jail.conf parser, written in awk 2020-12-05 21:15:48 +01:00
8 changed files with 1749 additions and 3505 deletions

View File

@@ -1,14 +0,0 @@
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

129
README.md
View File

@@ -1,32 +1,4 @@
## jaildk - a FreeBSD jail development kit v2.0.0 ## jaildk - a FreeBSD jail development kit
## 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.
@@ -140,72 +112,49 @@ 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: ./jaildk <command> <command-args> Usage: /usr/local/bin/jaildk <command> <mode-args>
Building Jails: Building Jails:
base -b <name> [-w] [-s <script>] - build a new base base -b <name> [-w] - build a new base
build <jail> -m <mode> [-b <base>] [-v <version>] - install a build chroot of a jail build <jail> <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
fetchports [-v <version>] - fetch current port collection fetch - fetch current port collection
(Un)installing Jails: Installing Jails:
install <jail> -m <mode> [-r function] - install a jail (prepare mounts, devfs etc) install <jail> <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> [-b <base>] [-v <version>] - stop, remove, install and start a jail, if reinstall <jail> - stop, remove, install and start a jail
-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>] [-v] - display status of jails or <jail> status [<jail>] - display a jail's status
rc <jail> -m <mode> [-r <rc.d script>] - execute an rc-script inside a jail rc <jail> <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 and internals: Getting help:
completion - print completion code. to use execute in a bash: help <command> - request help on <command>
source <(jaildk completion)
help <command> - request help on <command>
version - print program version
update [-f] - update jaildk from git repository
``` ```
## Installation ## Installation
Clone this repository to your FreeBSD server and execute the following command: Download the file `jaildk` or clone this repository to your FreeBSD server and execute the following command:
``` ```
make ./jaildk setup <directory>
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. The default base create a template jail and build a base directory.
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
@@ -372,7 +321,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 status myjail # jaildk startus 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
@@ -401,16 +350,15 @@ 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 clone of your jail with a new version: Now you can create 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 -m start -b `uname -r` -v 20210422 jaildk build myjail 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:
@@ -420,20 +368,9 @@ pkg update
... ...
``` ```
The last step is to remove the current running jail, change the The last step is to remove the current running jail, change the version in `etc/myjail.conf`, install and start the new version.
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
```
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 above steps.
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
@@ -592,11 +529,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 -m start -r pf` `jaildk install myjail start -r pf`
To take look at the rules, execute: To take look at the rules, execute:
`jaildk install myjail -m status -r pf` `jaildk install myjail 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

4
TODO
View File

@@ -1,4 +0,0 @@
- 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

View File

@@ -1,734 +0,0 @@
#!/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 Executable file

File diff suppressed because it is too large Load Diff

67
parse.sh Executable file
View File

@@ -0,0 +1,67 @@
#!/bin/sh
# parse /etc/jail.conf, better version
parse() {
file=$1
cat $file \
| awk '
/^\s*#/ {} # ignore comments and empty lines
/^\s*$/ {}
/^[a-zA-Z0-9\*]/ {
# extract the jail name
gsub(/\s*\{/, ""); # remove trailing parenthesis
gsub(/\*/, "any"); # rename *
jail = $0;
}
/=/ {
# key value pair
gsub(/^\s*/, ""); # remove leading spaces
gsub(/;.*/, ""); # remove trailing semicolong
gsub(/\s*=\s*/, "="); # remove spaces around =
if(/\.[a-zA-Z0-9_]*=/) {
# replace dot in variable name with underscore
sub(/\./, "_");
}
# extract key+value
split($0, pair, /=/);
key = pair[1];
value = pair[2];
# store into arrays
if(jail == "any") {
any[key] = value;
}
else {
j[jail][key] = value;
}
}
END {
output as shell code
for (jail in j) {
for (key in j[jail]) {
gsub(/\$name/, jail, j[jail][key])
printf "%s_%s=%s;\n", jail, key, j[jail][key]
}
for (anykey in any) {
if (! (jail, anykey) in j) {
gsub(/\$name/, jail, any[anykey])
printf "%s_%s=%s;\n", jail, anykey, any[anykey]
}
}
}
}'
}
parseconfig() {
code=`parse $1`
eval $code
}
parseconfig $1
echo "<${scippub_ip4_addr}>"

View File

@@ -1,108 +0,0 @@
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)

File diff suppressed because it is too large Load Diff