7 # REQUIRE: LOGIN FILESYSTEMS
9 # KEYWORD: nojail shutdown
14 desc="Manage system jails"
17 start_cmd="jail_start"
18 start_postcmd="jail_warn"
20 config_cmd="jail_config"
21 console_cmd="jail_console"
22 status_cmd="jail_status"
23 extra_commands="config console status"
24 : ${jail_conf:=/etc/jail.conf}
25 : ${jail_program:=/usr/sbin/jail}
26 : ${jail_consolecmd:=/usr/bin/login -f root}
27 : ${jail_jexec:=/usr/sbin/jexec}
28 : ${jail_jls:=/usr/sbin/jls}
32 # extract_var jv name param num defval
33 # Extract value from ${jail_$jv_$name} or ${jail_$name} and
34 # set it to $param. If not defined, $defval is used.
35 # When $num is [0-9]*, ${jail_$jv_$name$num} are looked up and
36 # $param is set by using +=. $num=0 is optional (params may start at 1).
37 # When $num is YN or NY, the value is interpreted as boolean.
38 # When $num is @, the value is interpreted as an array separted by IFS.
41 local i _jv _name _param _num _def _name1 _name2
50 _name1=jail_${_jv}_${_name}
52 eval $_name1=\"\${$_name1:-\${$_name2:-$_def}}\"
53 if checkyesno $_name1; then
60 _name1=jail_${_jv}_${_name}
62 eval $_name1=\"\${$_name1:-\${$_name2:-$_def}}\"
63 if checkyesno $_name1; then
72 _name1=jail_${_jv}_${_name}${i}
73 _name2=jail_${_name}${i}
74 eval _tmpargs=\"\${$_name1:-\${$_name2:-$_def}}\"
75 if [ -n "$_tmpargs" ]; then
76 echo " $_param += \"$_tmpargs\";"
77 elif [ $i != 0 ]; then
84 _name1=jail_${_jv}_${_name}
86 eval _tmpargs=\"\${$_name1:-\${$_name2:-$_def}}\"
90 while [ $# -gt 1 ]; do
98 _name1=jail_${_jv}_${_name}
100 eval _tmpargs=\"\${$_name1:-\${$_name2:-$_def}}\"
101 if [ -n "$_tmpargs" ]; then
102 echo " $_param = \"$_tmpargs\";"
108 # parse_options _j _jv
109 # Parse options and create a temporary configuration file if necessary.
118 if [ -z "$_j" ]; then
119 warn "parse_options: you must specify a jail"
122 eval _jconf=\"\${jail_${_jv}_conf:-/etc/jail.${_j}.conf}\"
123 eval _rootdir=\"\$jail_${_jv}_rootdir\"
124 eval _hostname=\"\$jail_${_jv}_hostname\"
125 if [ -z "$_rootdir" -o \
126 -z "$_hostname" ]; then
127 if [ -r "$_jconf" ]; then
130 elif [ -r "$jail_conf" ]; then
134 warn "Invalid configuration for $_j " \
135 "(no jail.conf, no hostname, or no path). " \
136 "Jail $_j was ignored."
140 eval _ip=\"\$jail_${_jv}_ip\"
141 if [ -z "$_ip" ] && ! check_kern_features vimage; then
142 warn "no ipaddress specified and no vimage support. " \
143 "Jail $_j was ignored."
146 _conf=/var/run/jail.${_j}.conf
148 # To relieve confusion, show a warning message.
150 : ${jail_confwarn:=YES}
151 checkyesno jail_confwarn && _confwarn=1
152 if [ -r "$jail_conf" -o -r "$_jconf" ]; then
153 if ! checkyesno jail_parallel_start; then
154 warn "$_conf is created and used for jail $_j."
157 /usr/bin/install -m 0644 -o root -g wheel /dev/null $_conf || return 1
159 eval : \${jail_${_jv}_flags:=${jail_flags}}
160 eval _exec=\"\$jail_${_jv}_exec\"
161 eval _exec_start=\"\$jail_${_jv}_exec_start\"
162 eval _exec_stop=\"\$jail_${_jv}_exec_stop\"
163 if [ -n "${_exec}" ]; then
164 # simple/backward-compatible execution
165 _exec_start="${_exec}"
169 if [ -z "${_exec_start}" ]; then
170 _exec_start="/bin/sh /etc/rc"
171 if [ -z "${_exec_stop}" ]; then
172 _exec_stop="/bin/sh /etc/rc.shutdown"
176 eval _interface=\"\${jail_${_jv}_interface:-${jail_interface}}\"
177 eval _parameters=\"\${jail_${_jv}_parameters:-${jail_parameters}}\"
178 eval _fstab=\"\${jail_${_jv}_fstab:-${jail_fstab:-/etc/fstab.$_j}}\"
180 date +"# Generated by rc.d/jail at %Y-%m-%d %H:%M:%S"
182 extract_var $_jv hostname host.hostname - ""
183 extract_var $_jv rootdir path - ""
184 if [ -n "$_ip" ]; then
185 extract_var $_jv interface interface - ""
186 jail_handle_ips_option $_ip $_interface
189 eval _x=\"\$jail_${_jv}_ip_multi${alias}\"
190 [ -z "$_x" ] && break
192 jail_handle_ips_option $_x $_interface
193 alias=$(($alias + 1))
195 case $need_dad_wait in
197 # Sleep to let DAD complete before
199 echo " exec.start += \"sleep " \
200 $(($(${SYSCTL_N} net.inet6.ip6.dad_count) + 1)) \
204 # These are applicable only to non-vimage jails.
205 extract_var $_jv fib exec.fib - ""
206 extract_var $_jv socket_unixiproute_only \
207 allow.raw_sockets NY YES
210 extract_var $_jv vnet_interface vnet.interface @ ""
214 echo " exec.system_user = \"root\";"
215 echo " exec.jail_user = \"root\";"
216 extract_var $_jv exec_prestart exec.prestart 0 ""
217 extract_var $_jv exec_poststart exec.poststart 0 ""
218 extract_var $_jv exec_prestop exec.prestop 0 ""
219 extract_var $_jv exec_poststop exec.poststop 0 ""
221 echo " exec.start += \"$_exec_start\";"
222 extract_var $_jv exec_afterstart exec.start 0 ""
223 echo " exec.stop = \"$_exec_stop\";"
225 extract_var $_jv consolelog exec.consolelog - \
226 /var/log/jail_${_j}_console.log
228 if [ -r $_fstab ]; then
229 echo " mount.fstab = \"$_fstab\";"
232 eval : \${jail_${_jv}_devfs_enable:=${jail_devfs_enable:-NO}}
233 if checkyesno jail_${_jv}_devfs_enable; then
235 eval _ruleset=\${jail_${_jv}_devfs_ruleset:-${jail_devfs_ruleset}}
238 [0-9]*) echo " devfs_ruleset = \"$_ruleset\";" ;;
240 # XXX: This is the default value,
241 # Let jail(8) to use the default because
242 # mount(8) only accepts an integer.
243 # This should accept a ruleset name.
245 *) warn "devfs_ruleset must be an integer." ;;
248 eval : \${jail_${_jv}_fdescfs_enable:=${jail_fdescfs_enable:-NO}}
249 if checkyesno jail_${_jv}_fdescfs_enable; then
250 echo " mount.fdescfs;"
252 eval : \${jail_${_jv}_procfs_enable:=${jail_procfs_enable:-NO}}
253 if checkyesno jail_${_jv}_procfs_enable; then
254 echo " mount.procfs;"
257 eval : \${jail_${_jv}_mount_enable:=${jail_mount_enable:-NO}}
258 if checkyesno jail_${_jv}_mount_enable; then
262 extract_var $_jv set_hostname_allow allow.set_hostname YN NO
263 extract_var $_jv sysvipc_allow allow.sysvipc YN NO
264 extract_var $_jv enforce_statfs enforce_statfs - 2
265 extract_var $_jv osreldate osreldate
266 extract_var $_jv osrelease osrelease
267 for _p in $_parameters; do
276 # jail_extract_address argument iface
277 # The second argument is the string from one of the _ip
278 # or the _multi variables. In case of a comma separated list
279 # only one argument must be passed in at a time.
280 # The function alters the _type, _iface, _addr and _mask variables.
282 jail_extract_address()
288 if [ -z "${_i}" ]; then
289 warn "jail_extract_address: called without input"
293 # Check if we have an interface prefix given and split into
296 *\|*) # ifN|.. prefix there
305 # In case the IP has no interface given, check if we have a global one.
306 _iface=${_iface:-${_interface}}
308 # Set address, cut off any prefix/netmask/prefixlen.
310 _addr=${_addr%%[/ ]*}
312 # Theoretically we can return here if interface is not set,
313 # as we only care about the _mask if we call ifconfig.
314 # This is not done because we may want to santize IP addresses
315 # based on _type later, and optionally change the type as well.
317 # Extract the prefix/netmask/prefixlen part by cutting off the address.
319 _mask=`expr "${_mask}" : "${_addr}\(.*\)"`
321 # Identify type {inet,inet6}.
323 *\.*\.*\.*) _type="inet" ;;
324 *:*) _type="inet6" ;;
325 *) warn "jail_extract_address: type not identified"
329 # Handle the special /netmask instead of /prefix or
330 # "netmask xxx" case for legacy IP.
331 # We do NOT support shortend class-full netmasks.
332 if [ "${_type}" = "inet" ]; then
334 /*\.*\.*\.*) _mask=" netmask ${_mask#/}" ;;
338 # In case _mask is still not set use /32.
341 elif [ "${_type}" = "inet6" ]; then
342 # In case _mask is not set for IPv6, use /128.
347 # jail_handle_ips_option input iface
348 # Handle a single argument imput which can be a comma separated
349 # list of addresses (theoretically with an option interface and
350 # prefix/netmask/prefixlen).
352 jail_handle_ips_option()
354 local _x _type _i _defif
358 if [ -z "${_x}" ]; then
359 # No IP given. This can happen for the primary address
360 # of each address family.
364 # Loop, in case we find a comma separated list, we need to handle
365 # each argument on its own.
366 while [ ${#_x} -gt 0 ]; do
368 *,*) # Extract the first argument and strip it off the list.
369 _i=`expr "${_x}" : '^\([^,]*\)'`
370 _x=`expr "${_x}" : "^[^,]*,\(.*\)"`
381 jail_extract_address $_i $_defif
383 # make sure we got an address.
389 # Append address to list of addresses for the jail command.
392 echo " ip4.addr += \"${_iface:+${_iface}|}${_addr}${_mask}\";"
395 echo " ip6.addr += \"${_iface:+${_iface}|}${_addr}${_mask}\";"
410 _j=$(echo $_j | tr /. _)
411 _jv=$(echo -n $_j | tr -c '[:alnum:]' _)
412 if parse_options $_j $_jv; then
413 echo "$_j: parameters are in $_conf."
422 # One argument that is not _ALL.
424 0:*|1:_ALL) err 3 "Specify a jail name." ;;
427 _j=$(echo $1 | tr /. _)
428 _jv=$(echo -n $1 | tr -c '[:alnum:]' _)
431 0) eval _cmd=\${jail_${_jv}_consolecmd:-$jail_consolecmd} ;;
434 $jail_jexec $_j $_cmd
445 local _j _jv _jid _id _name
450 echo -n 'Starting jails:'
453 command=$jail_program
455 command_args="-f $jail_conf -c"
456 if ! checkyesno jail_parallel_start; then
457 command_args="$command_args -p1"
459 _tmp=`mktemp -t jail` || exit 3
460 if $command $rc_flags $command_args >> $_tmp 2>&1; then
461 $jail_jls jid name | while read _id _name; do
463 echo $_id > /var/run/jail_${_name}.id
473 if checkyesno jail_parallel_start; then
475 # Start jails in parallel and then check jail id when
476 # jail_parallel_start is YES.
479 _j=$(echo $_j | tr /. _)
480 _jv=$(echo -n $_j | tr -c '[:alnum:]' _)
481 parse_options $_j $_jv || continue
483 eval rc_flags=\${jail_${_jv}_flags:-$jail_flags}
484 eval command=\${jail_${_jv}_program:-$jail_program}
485 command_args="-i -f $_conf -c $_j"
487 _tmp=`mktemp -t jail_${_j}` || exit 3
488 if $command $rc_flags $command_args \
489 >> $_tmp 2>&1 </dev/null; then
490 echo -n " ${_hostname:-${_j}}"
491 _jid=$($jail_jls -j $_j jid)
492 echo $_jid > /var/run/jail_${_j}.id
494 echo " cannot start jail " \
495 "\"${_hostname:-${_j}}\": "
504 # Start jails one-by-one when jail_parallel_start is NO.
507 _j=$(echo $_j | tr /. _)
508 _jv=$(echo -n $_j | tr -c '[:alnum:]' _)
509 parse_options $_j $_jv || continue
511 eval rc_flags=\${jail_${_jv}_flags:-$jail_flags}
512 eval command=\${jail_${_jv}_program:-$jail_program}
513 command_args="-i -f $_conf -c $_j"
514 _tmp=`mktemp -t jail` || exit 3
515 if $command $rc_flags $command_args \
516 >> $_tmp 2>&1 </dev/null; then
517 echo -n " ${_hostname:-${_j}}"
518 _jid=$($jail_jls -j $_j jid)
519 echo $_jid > /var/run/jail_${_j}.id
521 echo " cannot start jail " \
522 "\"${_hostname:-${_j}}\": "
538 echo -n 'Stopping jails:'
541 command=$jail_program
543 command_args="-f $jail_conf -r"
544 if checkyesno jail_reverse_stop; then
545 $jail_jls name | tail -r
548 fi | while read _j; do
550 _tmp=`mktemp -t jail` || exit 3
551 $command $rc_flags $command_args $_j >> $_tmp 2>&1
552 if $jail_jls -j $_j > /dev/null 2>&1; then
555 rm -f /var/run/jail_${_j}.id
563 checkyesno jail_reverse_stop && set -- $(reverse_list $@)
565 _j=$(echo $_j | tr /. _)
566 _jv=$(echo -n $_j | tr -c '[:alnum:]' _)
567 parse_options $_j $_jv || continue
568 if ! $jail_jls -j $_j > /dev/null 2>&1; then
571 eval command=\${jail_${_jv}_program:-$jail_program}
572 echo -n " ${_hostname:-${_j}}"
573 _tmp=`mktemp -t jail` || exit 3
574 $command -q -f $_conf -r $_j >> $_tmp 2>&1
575 if $jail_jls -j $_j > /dev/null 2>&1; then
578 rm -f /var/run/jail_${_j}.id
588 # To relieve confusion, show a warning message.
590 1) warn "Per-jail configuration via jail_* variables " \
591 "is obsolete. Please consider migrating to $jail_conf."
598 1) run_rc_command $@ ${jail_list:-_ALL} ;;
599 *) jail_reverse_stop="no"