jail revision 191620
113116Sbde#!/bin/sh
213116Sbde#
313116Sbde# $FreeBSD: head/etc/rc.d/jail 191620 2009-04-28 09:45:32Z ru $
413116Sbde#
513116Sbde
613116Sbde# PROVIDE: jail
713116Sbde# REQUIRE: LOGIN cleanvar
813116Sbde# BEFORE: securelevel
913116Sbde# KEYWORD: nojail shutdown
1013116Sbde
1113116Sbde# WARNING: This script deals with untrusted data (the data and
1213116Sbde# processes inside the jails) and care must be taken when changing the
1313116Sbde# code related to this!  If you have any doubt whether a change is
1413116Sbde# correct and have security impact, please get the patch reviewed by
1513116Sbde# the FreeBSD Security Team prior to commit.
1613116Sbde
1713116Sbde. /etc/rc.subr
1813116Sbde
1913116Sbdename="jail"
2013116Sbdercvar=`set_rcvar`
2113116Sbdestart_cmd="jail_start"
2213116Sbdestop_cmd="jail_stop"
2313116Sbde
2413116Sbde# init_variables _j
2513116Sbde#	Initialize the various jail variables for jail _j.
2613116Sbde#
2713116Sbdeinit_variables()
2813116Sbde{
291541Srgrimes	_j="$1"
30116189Sobrien
31116189Sobrien	if [ -z "$_j" ]; then
32116189Sobrien		warn "init_variables: you must specify a jail"
3313116Sbde		return
3413116Sbde	fi
3555206Speter
3619169Sbde	eval _rootdir=\"\$jail_${_j}_rootdir\"
3719169Sbde	_devdir="${_rootdir}/dev"
3819169Sbde	_fdescdir="${_devdir}/fd"
3913116Sbde	_procdir="${_rootdir}/proc"
4013116Sbde	eval _hostname=\"\$jail_${_j}_hostname\"
4113116Sbde	eval _ip=\"\$jail_${_j}_ip\"
4213116Sbde	eval _interface=\"\${jail_${_j}_interface:-${jail_interface}}\"
4313116Sbde	eval _exec=\"\$jail_${_j}_exec\"
4413116Sbde
4513116Sbde	i=0
4613116Sbde	while : ; do
4713116Sbde		eval _exec_prestart${i}=\"\${jail_${_j}_exec_prestart${i}:-\${jail_exec_prestart${i}}}\"
4813116Sbde		[ -z "$(eval echo \"\$_exec_prestart${i}\")" ] && break
4913116Sbde		i=$((i + 1))
5013116Sbde	done
5113116Sbde
5213116Sbde	eval _exec_start=\"\${jail_${_j}_exec_start:-${jail_exec_start}}\"
5313116Sbde
5413116Sbde	i=1
5513116Sbde	while [ true ]; do
5613116Sbde		eval _exec_afterstart${i}=\"\${jail_${_j}_exec_afterstart${i}:-\${jail_exec_afterstart${i}}}\"
5713116Sbde		[ -z "$(eval echo \"\$_exec_afterstart${i}\")" ] &&  break
5813116Sbde		i=$((i + 1))
5913116Sbde	done
60134398Smarcel
6113116Sbde	i=0
6213116Sbde	while : ; do
6319000Sbde		eval _exec_poststart${i}=\"\${jail_${_j}_exec_poststart${i}:-\${jail_exec_poststart${i}}}\"
6413116Sbde		[ -z "$(eval echo \"\$_exec_poststart${i}\")" ] && break
65134398Smarcel		i=$((i + 1))
66134398Smarcel	done
67134398Smarcel
68134398Smarcel	i=0
69134398Smarcel	while : ; do
7055206Speter		eval _exec_prestop${i}=\"\${jail_${_j}_exec_prestop${i}:-\${jail_exec_prestop${i}}}\"
7117879Sbde		[ -z "$(eval echo \"\$_exec_prestop${i}\")" ] && break
7213116Sbde		i=$((i + 1))
7313116Sbde	done
7413116Sbde
7513116Sbde	eval _exec_stop=\"\${jail_${_j}_exec_stop:-${jail_exec_stop}}\"
7613116Sbde
7713116Sbde	i=0
7813116Sbde	while : ; do
7913116Sbde		eval _exec_poststop${i}=\"\${jail_${_j}_exec_poststop${i}:-\${jail_exec_poststop${i}}}\"
8013116Sbde		[ -z "$(eval echo \"\$_exec_poststop${i}\")" ] && break
8113116Sbde		i=$((i + 1))
8213116Sbde	done
8355206Speter
8417879Sbde	if [ -n "${_exec}" ]; then
8513116Sbde		#   simple/backward-compatible execution
8613116Sbde		_exec_start="${_exec}"
8713116Sbde		_exec_stop=""
8813116Sbde	else
8955206Speter		#   flexible execution
9013116Sbde		if [ -z "${_exec_start}" ]; then
91134398Smarcel			_exec_start="/bin/sh /etc/rc"
92134398Smarcel			if [ -z "${_exec_stop}" ]; then
93134398Smarcel				_exec_stop="/bin/sh /etc/rc.shutdown"
9413116Sbde			fi
95134398Smarcel		fi
9655206Speter	fi
9713116Sbde
98134398Smarcel	# The default jail ruleset will be used by rc.subr if none is specified.
99134398Smarcel	eval _ruleset=\"\${jail_${_j}_devfs_ruleset:-${jail_devfs_ruleset}}\"
100134398Smarcel	eval _devfs=\"\${jail_${_j}_devfs_enable:-${jail_devfs_enable}}\"
101134398Smarcel	[ -z "${_devfs}" ] && _devfs="NO"
10213116Sbde	eval _fdescfs=\"\${jail_${_j}_fdescfs_enable:-${jail_fdescfs_enable}}\"
10319000Sbde	[ -z "${_fdescfs}" ] && _fdescfs="NO"
10419000Sbde	eval _procfs=\"\${jail_${_j}_procfs_enable:-${jail_procfs_enable}}\"
10519000Sbde	[ -z "${_procfs}" ] && _procfs="NO"
10619000Sbde
10719000Sbde	eval _mount=\"\${jail_${_j}_mount_enable:-${jail_mount_enable}}\"
10819000Sbde	[ -z "${_mount}" ] && _mount="NO"
10919000Sbde	# "/etc/fstab.${_j}" will be used for {,u}mount(8) if none is specified.
11019000Sbde	eval _fstab=\"\${jail_${_j}_fstab:-${jail_fstab}}\"
11119000Sbde	[ -z "${_fstab}" ] && _fstab="/etc/fstab.${_j}"
11219000Sbde	eval _flags=\"\${jail_${_j}_flags:-${jail_flags}}\"
11319000Sbde	[ -z "${_flags}" ] && _flags="-l -U root"
11419000Sbde	eval _consolelog=\"\${jail_${_j}_consolelog:-${jail_consolelog}}\"
11519000Sbde	[ -z "${_consolelog}" ] && _consolelog="/var/log/jail_${_j}_console.log"
11619000Sbde	eval _fib=\"\${jail_${_j}_fib:-${jail_fib}}\"
11719000Sbde
11819000Sbde	# Debugging aid
11919000Sbde	#
12019000Sbde	debug "$_j devfs enable: $_devfs"
12119000Sbde	debug "$_j fdescfs enable: $_fdescfs"
12219000Sbde	debug "$_j procfs enable: $_procfs"
12319000Sbde	debug "$_j mount enable: $_mount"
12419000Sbde	debug "$_j hostname: $_hostname"
12519000Sbde	debug "$_j ip: $_ip"
12619000Sbde	jail_show_addresses ${_j}
12719000Sbde	debug "$_j interface: $_interface"
12819000Sbde	debug "$_j fib: $_fib"
12913116Sbde	debug "$_j root: $_rootdir"
13013116Sbde	debug "$_j devdir: $_devdir"
13113116Sbde	debug "$_j fdescdir: $_fdescdir"
13255206Speter	debug "$_j procdir: $_procdir"
13313116Sbde	debug "$_j ruleset: $_ruleset"
13413116Sbde	debug "$_j fstab: $_fstab"
13513116Sbde	debug "$_j consolelog: $_consolelog"
136134398Smarcel
137134398Smarcel	i=0
138134398Smarcel	while : ; do
139134398Smarcel		eval out=\"\${_exec_prestart${i}:-''}\"
14013116Sbde		if [ -z "$out" ]; then
141134398Smarcel			break
142134398Smarcel		fi
143134398Smarcel		debug "$_j exec pre-start #${i}: ${out}"
14455206Speter		i=$((i + 1))
14513116Sbde	done
14613116Sbde
14713116Sbde	debug "$_j exec start: $_exec_start"
14813116Sbde
14913116Sbde	i=1
15013116Sbde	while [ true ]; do
15113116Sbde		eval out=\"\${_exec_afterstart${i}:-''}\"
15213116Sbde
15313116Sbde		if [ -z "$out" ]; then
15413116Sbde			break;
15513116Sbde		fi
15613116Sbde
15713116Sbde		debug "$_j exec after start #${i}: ${out}"
15813116Sbde		i=$((i + 1))
15913116Sbde	done
16013116Sbde
16113116Sbde	i=0
16213116Sbde	while : ; do
16313116Sbde		eval out=\"\${_exec_poststart${i}:-''}\"
16413116Sbde		if [ -z "$out" ]; then
16513116Sbde			break
16613116Sbde		fi
16713116Sbde		debug "$_j exec post-start #${i}: ${out}"
16813116Sbde		i=$((i + 1))
16913116Sbde	done
17013116Sbde
17113116Sbde	i=0
17213116Sbde	while : ; do
17313116Sbde		eval out=\"\${_exec_prestop${i}:-''}\"
17413116Sbde		if [ -z "$out" ]; then
17513116Sbde			break
17613116Sbde		fi
17713116Sbde		debug "$_j exec pre-stop #${i}: ${out}"
17813116Sbde		i=$((i + 1))
17913116Sbde	done
18013116Sbde
18113116Sbde	debug "$_j exec stop: $_exec_stop"
18213116Sbde
18313116Sbde	i=0
18413116Sbde	while : ; do
18513116Sbde		eval out=\"\${_exec_poststop${i}:-''}\"
18613116Sbde		if [ -z "$out" ]; then
18713116Sbde			break
18813116Sbde		fi
18913116Sbde		debug "$_j exec post-stop #${i}: ${out}"
19013116Sbde		i=$((i + 1))
19113116Sbde	done
19213116Sbde
19313116Sbde	debug "$_j flags: $_flags"
19413116Sbde	debug "$_j consolelog: $_consolelog"
19513116Sbde
19613116Sbde	if [ -z "${_hostname}" ]; then
19713116Sbde		err 3 "$name: No hostname has been defined for ${_j}"
19813116Sbde	fi
19913116Sbde	if [ -z "${_rootdir}" ]; then
20013116Sbde		err 3 "$name: No root directory has been defined for ${_j}"
20113116Sbde	fi
20213116Sbde}
20313116Sbde
20413116Sbde# set_sysctl rc_knob mib msg
20513116Sbde#	If the mib sysctl is set according to what rc_knob
20613116Sbde#	specifies, this function does nothing. However if
20713116Sbde#	rc_knob is set differently than mib, then the mib
20813116Sbde#	is set accordingly and msg is displayed followed by
20913116Sbde#	an '=" sign and the word 'YES' or 'NO'.
21013116Sbde#
21113116Sbdeset_sysctl()
21213116Sbde{
21313116Sbde	_knob="$1"
21413116Sbde	_mib="$2"
21513116Sbde	_msg="$3"
21613116Sbde
21713116Sbde	_current=`${SYSCTL} -n $_mib 2>/dev/null`
21813116Sbde	if checkyesno $_knob ; then
21913116Sbde		if [ "$_current" -ne 1 ]; then
22013116Sbde			echo -n " ${_msg}=YES"
22113116Sbde			${SYSCTL_W} 1>/dev/null ${_mib}=1
22213116Sbde		fi
22313116Sbde	else
22413116Sbde		if [ "$_current" -ne 0 ]; then
22513116Sbde			echo -n " ${_msg}=NO"
22655206Speter			${SYSCTL_W} 1>/dev/null ${_mib}=0
22717879Sbde		fi
22813116Sbde	fi
22913116Sbde}
23013116Sbde
23113116Sbde# is_current_mountpoint()
23213116Sbde#	Is the directory mount point for a currently mounted file
23313116Sbde#	system?
23455206Speter#
23517879Sbdeis_current_mountpoint()
23613116Sbde{
23713116Sbde	local _dir _dir2
23813116Sbde
23913116Sbde	_dir=$1
24013116Sbde
24113116Sbde	_dir=`echo $_dir | sed -Ee 's#//+#/#g' -e 's#/$##'`
24213116Sbde	[ ! -d "${_dir}" ] && return 1
24313116Sbde	_dir2=`df ${_dir} | tail +2 | awk '{ print $6 }'`
24413116Sbde	[ "${_dir}" = "${_dir2}" ]
24513116Sbde	return $?
24613116Sbde}
24713116Sbde
24813116Sbde# is_symlinked_mountpoint()
24937629Sbde#	Is a mount point, or any of its parent directories, a symlink?
25013116Sbde#
25113116Sbdeis_symlinked_mountpoint()
25237629Sbde{
25313116Sbde	local _dir
25413116Sbde
25537629Sbde	_dir=$1
25613116Sbde
25719000Sbde	[ -L "$_dir" ] && return 0
25813116Sbde	[ "$_dir" = "/" ] && return 1
25913116Sbde	is_symlinked_mountpoint `dirname $_dir`
26019000Sbde	return $?
26119000Sbde}
26213116Sbde
26319000Sbde# secure_umount
26419000Sbde#	Try to unmount a mount point without being vulnerable to
26519000Sbde#	symlink attacks.
26613116Sbde#
26719000Sbdesecure_umount()
26813116Sbde{
26913116Sbde	local _dir
27019000Sbde
271170659Sbde	_dir=$1
272170659Sbde
273170659Sbde	if is_current_mountpoint ${_dir}; then
274170659Sbde		umount -f ${_dir} >/dev/null 2>&1
27519000Sbde	else
27619000Sbde		debug "Nothing mounted on ${_dir} - not unmounting"
27719000Sbde	fi
27819000Sbde}
27919000Sbde
28019000Sbde
281170659Sbde# jail_umount_fs
28219000Sbde#	This function unmounts certain special filesystems in the
28319000Sbde#	currently selected jail. The caller must call the init_variables()
28419000Sbde#	routine before calling this one.
28519000Sbde#
28619000Sbdejail_umount_fs()
287170659Sbde{
28819000Sbde	local _device _mountpt _rest
28919000Sbde
29019000Sbde	if checkyesno _fdescfs; then
29119000Sbde		if [ -d "${_fdescdir}" ] ; then
29219000Sbde			secure_umount ${_fdescdir}
29319000Sbde		fi
29419000Sbde	fi
29519000Sbde	if checkyesno _devfs; then
29619000Sbde		if [ -d "${_devdir}" ] ; then
29719000Sbde			secure_umount ${_devdir}
29813116Sbde		fi
299	fi
300	if checkyesno _procfs; then
301		if [ -d "${_procdir}" ] ; then
302			secure_umount ${_procdir}
303		fi
304	fi
305	if checkyesno _mount; then
306		[ -f "${_fstab}" ] || warn "${_fstab} does not exist"
307		tail -r ${_fstab} | while read _device _mountpt _rest; do
308			case ":${_device}" in
309			:#* | :)
310				continue
311				;;
312			esac
313			secure_umount ${_mountpt}
314		done
315	fi
316}
317
318# jail_mount_fstab()
319#	Mount file systems from a per jail fstab while trying to
320#	secure against symlink attacks at the mount points.
321#
322#	If we are certain we cannot secure against symlink attacks we
323#	do not mount all of the file systems (since we cannot just not
324#	mount the file system with the problematic mount point).
325#
326#	The caller must call the init_variables() routine before
327#	calling this one.
328#
329jail_mount_fstab()
330{
331	local _device _mountpt _rest
332
333	while read _device _mountpt _rest; do
334		case ":${_device}" in
335		:#* | :)
336			continue
337			;;
338		esac
339		if is_symlinked_mountpoint ${_mountpt}; then
340			warn "${_mountpt} has symlink as parent - not mounting from ${_fstab}"
341			return
342		fi
343	done <${_fstab}
344	mount -a -F "${_fstab}"
345}
346
347# jail_show_addresses jail
348#	Debug print the input for the given _multi aliases
349#	for a jail for init_variables().
350#
351jail_show_addresses()
352{
353	local _j _type alias
354	_j="$1"
355	alias=0
356
357	if [ -z "${_j}" ]; then
358		warn "jail_show_addresses: you must specify a jail"
359		return
360	fi
361
362	while : ; do
363		eval _addr=\"\$jail_${_j}_ip_multi${alias}\"
364		if [ -n "${_addr}" ]; then
365			debug "${_j} ip_multi${alias}: $_addr"
366			alias=$((${alias} + 1))
367		else
368			break
369		fi
370	done
371}
372
373# jail_extract_address argument
374#	The second argument is the string from one of the _ip
375#	or the _multi variables. In case of a comma separated list
376#	only one argument must be passed in at a time.
377#	The function alters the _type, _iface, _addr and _mask variables.
378#
379jail_extract_address()
380{
381	local _i
382	_i=$1
383
384	if [ -z "${_i}" ]; then
385		warn "jail_extract_address: called without input"
386		return
387	fi
388
389	# Check if we have an interface prefix given and split into
390	# iFace and rest.
391	case "${_i}" in
392	*\|*)	# ifN|.. prefix there
393		_iface=${_i%%|*}
394		_r=${_i##*|}
395		;;
396	*)	_iface=""
397		_r=${_i}
398		;;
399	esac
400
401	# In case the IP has no interface given, check if we have a global one.
402	_iface=${_iface:-${_interface}}
403
404	# Set address, cut off any prefix/netmask/prefixlen.
405	_addr=${_r}
406	_addr=${_addr%%[/ ]*}
407
408	# Theoretically we can return here if interface is not set,
409	# as we only care about the _mask if we call ifconfig.
410	# This is not done because we may want to santize IP addresses
411	# based on _type later, and optionally change the type as well.
412
413	# Extract the prefix/netmask/prefixlen part by cutting off the address.
414	_mask=${_r}
415	_mask=`expr "${_mask}" : "${_addr}\(.*\)"`
416
417	# Identify type {inet,inet6}.
418	case "${_addr}" in
419	*\.*\.*\.*)	_type="inet" ;;
420	*:*)		_type="inet6" ;;
421	*)		warn "jail_extract_address: type not identified"
422			;;
423	esac
424
425	# Handle the special /netmask instead of /prefix or
426	# "netmask xxx" case for legacy IP.
427	# We do NOT support shortend class-full netmasks.
428	if [ "${_type}" = "inet" ]; then
429		case "${_mask}" in
430		/*\.*\.*\.*)	_mask=" netmask ${_mask#/}" ;;
431		*)		;;
432		esac
433
434		# In case _mask is still not set use /32.
435		_mask=${_mask:-/32}
436
437	elif [ "${_type}" = "inet6" ]; then
438		# In case _maske is not set for IPv6, use /128.
439		_mask=${_mask:-/128}
440	fi
441}
442
443# jail_handle_ips_option {add,del} input
444#	Handle a single argument imput which can be a comma separated
445#	list of addresses (theoretically with an option interface and
446#	prefix/netmask/prefixlen).
447#
448jail_handle_ips_option()
449{
450	local _x _action _type _i
451	_action=$1
452	_x=$2
453
454	if [ -z "${_x}" ]; then
455		# No IP given. This can happen for the primary address
456		# of each address family.
457		return
458	fi
459
460	# Loop, in case we find a comma separated list, we need to handle
461	# each argument on its own.
462	while [ ${#_x} -gt 0 ]; do
463		case "${_x}" in
464		*,*)	# Extract the first argument and strip it off the list.
465			_i=`expr "${_x}" : '^\([^,]*\)'`
466			_x=`expr "${_x}" : "^[^,]*,\(.*\)"`
467			;;
468		*)	_i=${_x}
469			_x=""
470			;;
471		esac
472
473		_type=""
474		_iface=""
475		_addr=""
476		_mask=""
477		jail_extract_address "${_i}"
478
479		# make sure we got an address.
480		case "${_addr}" in
481		"")	continue ;;
482		*)	;;
483		esac
484
485		# Append address to list of addresses for the jail command.
486		case "${_addrl}" in
487		"")	_addrl="${_addr}" ;;
488		*)	_addrl="${_addrl},${_addr}" ;;
489		esac
490
491		# Configure interface alias if requested by a given interface
492		# and if we could correctly parse everything.
493		case "${_iface}" in
494		"")	continue ;;
495		esac
496		case "${_type}" in
497		inet)	;;
498		inet6)	;;
499		*)	warn "Could not determine address family.  Not going" \
500			    "to ${_action} address '${_addr}' for ${_jail}."
501			continue
502			;;
503		esac
504		case "${_action}" in
505		add)	ifconfig ${_iface} ${_type} ${_addr}${_mask} alias
506			;;
507		del)	# When removing the IP, ignore the _mask.
508			ifconfig ${_iface} ${_type} ${_addr} -alias
509			;;
510		esac
511	done
512}
513
514# jail_ips {add,del}
515#	Extract the comma separated list of addresses and return them
516#	for the jail command.
517#	Handle more than one address via the _multi option as well.
518#	If an interface is given also add/remove an alias for the
519#	address with an optional netmask.
520#
521jail_ips()
522{
523	local _action
524	_action=$1
525
526	case "${_action}" in
527	add)	;;
528	del)	;;
529	*)	warn "jail_ips: invalid action '${_action}'"
530		return
531		;;
532	esac
533
534	# Handle addresses.
535	jail_handle_ips_option ${_action} "${_ip}"
536	# Handle jail_xxx_ip_multi<N>
537	alias=0
538	while : ; do
539		eval _x=\"\$jail_${_jail}_ip_multi${alias}\"
540		case "${_x}" in
541		"")	break ;;
542		*)	jail_handle_ips_option ${_action} "${_x}"
543			alias=$((${alias} + 1))
544			;;
545		esac
546	done
547}
548
549jail_start()
550{
551	echo -n 'Configuring jails:'
552	set_sysctl jail_set_hostname_allow security.jail.set_hostname_allowed \
553	    set_hostname_allow
554	set_sysctl jail_socket_unixiproute_only \
555	    security.jail.socket_unixiproute_only unixiproute_only
556	set_sysctl jail_sysvipc_allow security.jail.sysvipc_allowed \
557	    sysvipc_allow
558	echo '.'
559
560	echo -n 'Starting jails:'
561	_tmp_dir=`mktemp -d /tmp/jail.XXXXXXXX` || \
562	    err 3 "$name: Can't create temp dir, exiting..."
563	for _jail in ${jail_list}
564	do
565		init_variables $_jail
566		if [ -f /var/run/jail_${_jail}.id ]; then
567			echo -n " [${_hostname} already running (/var/run/jail_${_jail}.id exists)]"
568			continue;
569		fi
570		_addrl=""
571		jail_ips "add"
572		if [ -n "${_fib}" ]; then
573			_setfib="setfib -F '${_fib}'"
574		else
575			_setfib=""
576		fi
577		if checkyesno _mount; then
578			info "Mounting fstab for jail ${_jail} (${_fstab})"
579			if [ ! -f "${_fstab}" ]; then
580				err 3 "$name: ${_fstab} does not exist"
581			fi
582			jail_mount_fstab
583		fi
584		if checkyesno _devfs; then
585			# If devfs is already mounted here, skip it.
586			df -t devfs "${_devdir}" >/dev/null
587			if [ $? -ne 0 ]; then
588				if is_symlinked_mountpoint ${_devdir}; then
589					warn "${_devdir} has symlink as parent - not starting jail ${_jail}"
590					continue
591				fi
592				info "Mounting devfs on ${_devdir}"
593				devfs_mount_jail "${_devdir}" ${_ruleset}
594				# Transitional symlink for old binaries
595				if [ ! -L "${_devdir}/log" ]; then
596					__pwd="`pwd`"
597					cd "${_devdir}"
598					ln -sf ../var/run/log log
599					cd "$__pwd"
600				fi
601			fi
602
603			# XXX - It seems symlinks don't work when there
604			#	is a devfs(5) device of the same name.
605			# Jail console output
606			#	__pwd="`pwd`"
607			#	cd "${_devdir}"
608			#	ln -sf ../var/log/console console
609			#	cd "$__pwd"
610		fi
611		if checkyesno _fdescfs; then
612			if is_symlinked_mountpoint ${_fdescdir}; then
613				warn "${_fdescdir} has symlink as parent, not mounting"
614			else
615				info "Mounting fdescfs on ${_fdescdir}"
616				mount -t fdescfs fdesc "${_fdescdir}"
617			fi
618		fi
619		if checkyesno _procfs; then
620			if is_symlinked_mountpoint ${_procdir}; then
621				warn "${_procdir} has symlink as parent, not mounting"
622			else
623				info "Mounting procfs onto ${_procdir}"
624				if [ -d "${_procdir}" ] ; then
625					mount -t procfs proc "${_procdir}"
626				fi
627			fi
628		fi
629		_tmp_jail=${_tmp_dir}/jail.$$
630
631		i=0
632		while : ; do
633			eval out=\"\${_exec_prestart${i}:-''}\"
634			[ -z "$out" ] && break
635			${out}
636			i=$((i + 1))
637		done
638
639		eval ${_setfib} jail ${_flags} -i ${_rootdir} ${_hostname} \
640			\"${_addrl}\" ${_exec_start} > ${_tmp_jail} 2>&1
641
642		if [ "$?" -eq 0 ] ; then
643			_jail_id=$(head -1 ${_tmp_jail})
644			i=1
645			while [ true ]; do
646				eval out=\"\${_exec_afterstart${i}:-''}\"
647
648				if [ -z "$out" ]; then
649					break;
650				fi
651
652				jexec "${_jail_id}" ${out}
653				i=$((i + 1))
654			done
655
656			echo -n " $_hostname"
657			tail +2 ${_tmp_jail} >${_consolelog}
658			echo ${_jail_id} > /var/run/jail_${_jail}.id
659
660			i=0
661			while : ; do
662				eval out=\"\${_exec_poststart${i}:-''}\"
663				[ -z "$out" ] && break
664				${out}
665				i=$((i + 1))
666			done
667		else
668			jail_umount_fs
669			jail_ips "del"
670			echo " cannot start jail \"${_jail}\": "
671			tail +2 ${_tmp_jail}
672		fi
673		rm -f ${_tmp_jail}
674	done
675	rmdir ${_tmp_dir}
676	echo '.'
677}
678
679jail_stop()
680{
681	echo -n 'Stopping jails:'
682	for _jail in ${jail_list}
683	do
684		if [ -f "/var/run/jail_${_jail}.id" ]; then
685			_jail_id=$(cat /var/run/jail_${_jail}.id)
686			if [ ! -z "${_jail_id}" ]; then
687				init_variables $_jail
688
689				i=0
690				while : ; do
691					eval out=\"\${_exec_prestop${i}:-''}\"
692					[ -z "$out" ] && break
693					${out}
694					i=$((i + 1))
695				done
696
697				if [ -n "${_exec_stop}" ]; then
698					eval env -i /usr/sbin/jexec ${_jail_id} ${_exec_stop} \
699						>> ${_consolelog} 2>&1
700				fi
701				killall -j ${_jail_id} -TERM > /dev/null 2>&1
702				sleep 1
703				killall -j ${_jail_id} -KILL > /dev/null 2>&1
704				jail_umount_fs
705				echo -n " $_hostname"
706
707				i=0
708				while : ; do
709					eval out=\"\${_exec_poststop${i}:-''}\"
710					[ -z "$out" ] && break
711					${out}
712					i=$((i + 1))
713				done
714			fi
715			jail_ips "del"
716			rm /var/run/jail_${_jail}.id
717		else
718			echo " cannot stop jail ${_jail}. No jail id in /var/run"
719		fi
720	done
721	echo '.'
722}
723
724load_rc_config $name
725cmd="$1"
726if [ $# -gt 0 ]; then
727	shift
728fi
729if [ -n "$*" ]; then
730	jail_list="$*"
731fi
732run_rc_command "${cmd}"
733