appjail-initscript
—
Jail automation script
An InitScript is an
sh(1)
script that has functions with a special meaning that are executed in
specific operations.
InitScripts
are the core of
Makejails,
as the latter generate the former.
Each stage has a pre- and
post- function that are executed before the main function
is executed and after the main function is executed, e.g.
create
can have
precreate
and
postcreate.
pre- is executed before the stage is executed
and if it fails, the stage will not be executed. post-
will be executed after pre- and the stage even if they
fail. pre- and the stage affect the exit status, but
post- does not.
Without user input an InitScript is meaningless,
but the way external commands like
appjail-start(1),
appjail-stop(1),
appjail-run(1)
and
appjail-apply(1)
pass arguments is a bit different than an
sh(1)
script.
Each parameter begins with a double dash followed by
an arbitrary string followed by the value. For example, the parameter
foo=bar will be
expressed internally as --foo
"bar".
Each pre- and post- stage will
receive the same parameters as the main stage.
See EXAMPLES for more
details.
An InitScript is as powerful as any other
sh(1)
script, the problem is that although the built-in environment variables can
help, they are not enough for some common tasks, that's why there is a
“library” with some subroutines you can use, inspired by
appjail-makejail(5).
INITENV
- After this function finishes executing, commands such as
CMD
will use the environment variables according
to the -V
parameter in commands such as
appjail-start(1),
appjail-stop(1)
and
appjail-run(1).
If you want to respect the environment variables provided by
the user, you must call this function after ENV
,
in case you call the last function.
ENV
name [value]
- Sets another environment variable for use in commands such as
CMD
.
CMD
[-l
] [[-e
name=[value]]
...] [-u
username] [-w
workdir] command
[args ...]
- Execute a command inside the jail.
-l
- Unlike
jexec(8)'s
-l
, this indicates not to clean the
environment.
-e
name=[value]
- Sets an environment variable only for the call to this function.
Environment variables defined by this parameter take precedence over
INITENV
or ENV
.
-u
username
- Username to execute the command as.
-w
workdir
- Working directory. See also
WORKDIR
.
LOCAL
[[-j
|-r
]]
command [args
...]
- Execute a command from the host but within the jail directory
(
-j
) or the root directory of the jail
(-r
).
CHROOT
command [args
...]
- Execute a command using
appjail-cmd(1)
chroot
.
JAILDIR
command [args
...]
- Execute a command using
appjail-cmd(1)
jaildir
.
PKG
[[-c
|-j
]]
args ...
- Manipulate packages within a jail.
By default,
appjail-pkg(1)
jail
is used, but you can change it to
appjail-pkg(1)
chroot
when using -c
instead. Use -j
to use
pkg(8)
from inside the jail instead of the host.
ARG
name [default-value]
- Defines a new parameter that can be parsed using
PARSE
. Unlike the ARG
instruction of
appjail-makejail(5),
there is no such thing as a required argument, but you can easily check
whether a variable is defined or not using utilities like
test(1).
You can access variable values using a
syntax like
${ARG_<name>}
or
$ARG_<name>.
PARSE
[args ...]
- Parse the arguments. You must pass the arguments of the stage as arguments
to this function.
VOLUME
[-g
group]
[-m
mountpoint]
[-o
owner]
[-p
perm]
[-t
type]
name
- See
appjail-volume(1).
DEVICE:SET
args ...
- See
appjail-devfs(1)
set
.
DEVICE:APPLYSET
- See
appjail-devfs(1)
applyset
.
LABEL:ADD
name [value]
- See
appjail-label(1)
add
.
LABEL:GET
name
- Get the value of a label. If the label does not exist, an empty value is
returned and the exit status is modified accordingly.
MOUNT
[-MP
] [-n
nro] device
mountpoint [type
[options [dump
[pass]]]]
- Use
appjail-fstab(1)
to create a new entry in the
fstab(5)
of the jail and, unless the
-M
parameter is set,
the file will be compiled and the entries mounted. If the
-P
parameter is specified,
mount(8)
is used instead.
UMOUNT
mountpoint
- See
umount(8).
mountpoint is a mount point relative to
the jail directory.
REPLACE
file keyword
[value] [output]
- Replace a given keyword (without being enclosed in
%{
and
}) with a
value (or empty, if not defined) in a
file. Keywords begin with the %
character and then the keyword name enclosed in curly braces. Use
% twice to escape, for example
%%{KEYWORD}
will be converted to
%{KEYWORD},
but will not be replaced by any value. A different file can be used as
output for the replaced keywords.
SERVICE
args ...
- See
appjail-service(1).
SYSRC
[-l
] args
...
- See
appjail-sysrc(1).
If -l
is specified,
appjail-sysrc(1)
local
is used instead of
appjail-sysrc(1)
jail
.
WORKDIR
directory
- Sets the working directory of commands such as
REPLACE
and CMD
.
- ${LIBDIR}/initscript
- File with some common subroutines.
The following InitScript is used to show how
parameters and arguments are passed.
$PWD/initscript.sh:
_parse_args()
{
local arg
for arg in "$@"; do
printf "<%s> " "${arg}"
done
echo
}
precreate()
{
echo -n "precreate args: "
_parse_args "$@"
}
create()
{
echo -n "create args: "
_parse_args "$@"
}
postcreate()
{
echo -n "postcreate args: "
_parse_args "$@"
}
prestart()
{
echo -n "prestart args: "
_parse_args "$@"
}
start()
{
echo -n "start args: "
_parse_args "$@"
}
poststart()
{
echo -n "poststart args: "
_parse_args "$@"
}
precmd()
{
echo -n "precmd args: "
_parse_args "$@"
}
cmd()
{
echo -n "cmd args: "
_parse_args "$@"
}
postcmd()
{
echo -n "postcmd args: "
_parse_args "$@"
}
prestop()
{
echo -n "prestop args: "
_parse_args "$@"
}
stop()
{
echo -n "stop args: "
_parse_args "$@"
}
poststop()
{
echo -n "poststop args: "
_parse_args "$@"
}
# appjail quick
jtest overwrite
initscript
=$PWD/initscript.sh
# appjail start
\
-c
'parameter1=I am the <create> parameter #1' \
-c
'parameter2=I am the <create> parameter #2' \
-s
'parameter1=I am the <start> parameter #1' \
-s
'parameter2=I am the <start> parameter #2' \
jtest
...
[00:00:01] [ debug ] [jtest] Running initscript `/usr/local/appjail/jails/jtest/init` ...
[00:00:01] [ debug ] [jtest] Running precreate() ...
precreate args: <--parameter1> <I am the <create> parameter #1> <--parameter2> <I am the <create> parameter #2>
[00:00:01] [ debug ] [jtest] precreate() exits with status code 0
create args: <--parameter1> <I am the <create> parameter #1> <--parameter2> <I am the <create> parameter #2>
[00:00:01] [ debug ] [jtest] create() exits with status code 0
postcreate args: <--parameter1> <I am the <create> parameter #1> <--parameter2> <I am the <create> parameter #2>
[00:00:01] [ debug ] [jtest] postcreate() exits with status code 0
[00:00:01] [ debug ] [jtest] `/usr/local/appjail/jails/jtest/init` exits with status code 0
[00:00:01] [ debug ] [jtest] Creating...
jtest: created
[00:00:01] [ debug ] [jtest] Running initscript `/usr/local/appjail/jails/jtest/init` ...
[00:00:01] [ debug ] [jtest] Running prestart() ...
prestart args: <--parameter1> <I am the <start> parameter #1> <--parameter2> <I am the <start> parameter #2>
[00:00:01] [ debug ] [jtest] prestart() exits with status code 0
start args: <--parameter1> <I am the <start> parameter #1> <--parameter2> <I am the <start> parameter #2>
[00:00:01] [ debug ] [jtest] start() exits with status code 0
poststart args: <--parameter1> <I am the <start> parameter #1> <--parameter2> <I am the <start> parameter #2>
[00:00:01] [ debug ] [jtest] poststart() exits with status code 0
[00:00:01] [ debug ] [jtest] `/usr/local/appjail/jails/jtest/init` exits with status code 0
...
# appjail run
-p
'msg=Hello, world!' jtest
[00:00:01] [ debug ] [jtest] Running initscript `/usr/local/appjail/jails/jtest/init` ...
[00:00:01] [ debug ] [jtest] Running precmd() ...
precmd args: <--msg> <Hello, world!>
[00:00:01] [ debug ] [jtest] precmd() exits with status code 0
cmd args: <--msg> <Hello, world!>
[00:00:01] [ debug ] [jtest] cmd() exits with status code 0
postcmd args: <--msg> <Hello, world!>
[00:00:01] [ debug ] [jtest] postcmd() exits with status code 0
[00:00:01] [ debug ] [jtest] `/usr/local/appjail/jails/jtest/init` exits with status code 0
# appjail stop
-p
'msg=Bye ...' jtest
[00:00:01] [ debug ] [jtest] Running initscript `/usr/local/appjail/jails/jtest/init` ...
[00:00:01] [ debug ] [jtest] Running prestop() ...
prestop args: <--msg> <Bye ...>
[00:00:01] [ debug ] [jtest] prestop() exits with status code 0
stop args: <--msg> <Bye ...>
[00:00:01] [ debug ] [jtest] stop() exits with status code 0
poststop args: <--msg> <Bye ...>
[00:00:01] [ debug ] [jtest] poststop() exits with status code 0
[00:00:01] [ debug ] [jtest] `/usr/local/appjail/jails/jtest/init` exits with status code 0
[00:00:01] [ warn ] [jtest] Stopping jtest...
jtest: removed
[00:00:01] [ debug ] [jtest] unmounting: umount "/usr/local/appjail/jails/jtest/jail/.appjail"
appjail(1)
runs the InitScript from the host instead of in the jail,
so it needs to explicitly call
jexec(8).
The reason is that this allows you to perform some tasks for both the host
and the jail much more easily, e.g. mount a filesystem dynamically. The
problem is that you should not call with a fixed string, such as the jail
name, as this can cause the jail name to be changed to any other arbitrary
string. The solution is not really difficult: use environment variables that
are best described in ENVIRONMENT.
cmd()
{
jexec -l "${APPJAIL_JAILNAME}" sh -c 'echo "Hello, world!"'
}