]> CyberLeo.Net >> Repos - FreeBSD/releng/9.0.git/blob - etc/rc.d/jail
Copy stable/9 to releng/9.0 as part of the FreeBSD 9.0-RELEASE release
[FreeBSD/releng/9.0.git] / etc / rc.d / jail
1 #!/bin/sh
2 #
3 # $FreeBSD$
4 #
5
6 # PROVIDE: jail
7 # REQUIRE: LOGIN cleanvar
8 # BEFORE: securelevel
9 # KEYWORD: nojail shutdown
10
11 # WARNING: This script deals with untrusted data (the data and
12 # processes inside the jails) and care must be taken when changing the
13 # code related to this!  If you have any doubt whether a change is
14 # correct and have security impact, please get the patch reviewed by
15 # the FreeBSD Security Team prior to commit.
16
17 . /etc/rc.subr
18
19 name="jail"
20 rcvar=`set_rcvar`
21
22 start_precmd="jail_prestart"
23 start_cmd="jail_start"
24 stop_cmd="jail_stop"
25
26 # init_variables _j
27 #       Initialize the various jail variables for jail _j.
28 #
29 init_variables()
30 {
31         _j="$1"
32
33         if [ -z "$_j" ]; then
34                 warn "init_variables: you must specify a jail"
35                 return
36         fi
37
38         eval _rootdir=\"\$jail_${_j}_rootdir\"
39         _devdir="${_rootdir}/dev"
40         _fdescdir="${_devdir}/fd"
41         _procdir="${_rootdir}/proc"
42         eval _hostname=\"\$jail_${_j}_hostname\"
43         eval _ip=\"\$jail_${_j}_ip\"
44         eval _interface=\"\${jail_${_j}_interface:-${jail_interface}}\"
45         eval _exec=\"\$jail_${_j}_exec\"
46
47         i=0
48         while : ; do
49                 eval _exec_prestart${i}=\"\${jail_${_j}_exec_prestart${i}:-\${jail_exec_prestart${i}}}\"
50                 [ -z "$(eval echo \"\$_exec_prestart${i}\")" ] && break
51                 i=$((i + 1))
52         done
53
54         eval _exec_start=\"\${jail_${_j}_exec_start:-${jail_exec_start}}\"
55
56         i=1
57         while : ; do
58                 eval _exec_afterstart${i}=\"\${jail_${_j}_exec_afterstart${i}:-\${jail_exec_afterstart${i}}}\"
59                 [ -z "$(eval echo \"\$_exec_afterstart${i}\")" ] &&  break
60                 i=$((i + 1))
61         done
62
63         i=0
64         while : ; do
65                 eval _exec_poststart${i}=\"\${jail_${_j}_exec_poststart${i}:-\${jail_exec_poststart${i}}}\"
66                 [ -z "$(eval echo \"\$_exec_poststart${i}\")" ] && break
67                 i=$((i + 1))
68         done
69
70         i=0
71         while : ; do
72                 eval _exec_prestop${i}=\"\${jail_${_j}_exec_prestop${i}:-\${jail_exec_prestop${i}}}\"
73                 [ -z "$(eval echo \"\$_exec_prestop${i}\")" ] && break
74                 i=$((i + 1))
75         done
76
77         eval _exec_stop=\"\${jail_${_j}_exec_stop:-${jail_exec_stop}}\"
78
79         i=0
80         while : ; do
81                 eval _exec_poststop${i}=\"\${jail_${_j}_exec_poststop${i}:-\${jail_exec_poststop${i}}}\"
82                 [ -z "$(eval echo \"\$_exec_poststop${i}\")" ] && break
83                 i=$((i + 1))
84         done
85
86         if [ -n "${_exec}" ]; then
87                 #   simple/backward-compatible execution
88                 _exec_start="${_exec}"
89                 _exec_stop=""
90         else
91                 #   flexible execution
92                 if [ -z "${_exec_start}" ]; then
93                         _exec_start="/bin/sh /etc/rc"
94                         if [ -z "${_exec_stop}" ]; then
95                                 _exec_stop="/bin/sh /etc/rc.shutdown"
96                         fi
97                 fi
98         fi
99
100         # The default jail ruleset will be used by rc.subr if none is specified.
101         eval _ruleset=\"\${jail_${_j}_devfs_ruleset:-${jail_devfs_ruleset}}\"
102         eval _devfs=\"\${jail_${_j}_devfs_enable:-${jail_devfs_enable}}\"
103         [ -z "${_devfs}" ] && _devfs="NO"
104         eval _fdescfs=\"\${jail_${_j}_fdescfs_enable:-${jail_fdescfs_enable}}\"
105         [ -z "${_fdescfs}" ] && _fdescfs="NO"
106         eval _procfs=\"\${jail_${_j}_procfs_enable:-${jail_procfs_enable}}\"
107         [ -z "${_procfs}" ] && _procfs="NO"
108
109         eval _mount=\"\${jail_${_j}_mount_enable:-${jail_mount_enable}}\"
110         [ -z "${_mount}" ] && _mount="NO"
111         # "/etc/fstab.${_j}" will be used for {,u}mount(8) if none is specified.
112         eval _fstab=\"\${jail_${_j}_fstab:-${jail_fstab}}\"
113         [ -z "${_fstab}" ] && _fstab="/etc/fstab.${_j}"
114         eval _flags=\"\${jail_${_j}_flags:-${jail_flags}}\"
115         [ -z "${_flags}" ] && _flags="-l -U root"
116         eval _consolelog=\"\${jail_${_j}_consolelog:-${jail_consolelog}}\"
117         [ -z "${_consolelog}" ] && _consolelog="/var/log/jail_${_j}_console.log"
118         eval _fib=\"\${jail_${_j}_fib:-${jail_fib}}\"
119
120         # Debugging aid
121         #
122         debug "$_j devfs enable: $_devfs"
123         debug "$_j fdescfs enable: $_fdescfs"
124         debug "$_j procfs enable: $_procfs"
125         debug "$_j mount enable: $_mount"
126         debug "$_j hostname: $_hostname"
127         debug "$_j ip: $_ip"
128         jail_show_addresses ${_j}
129         debug "$_j interface: $_interface"
130         debug "$_j fib: $_fib"
131         debug "$_j root: $_rootdir"
132         debug "$_j devdir: $_devdir"
133         debug "$_j fdescdir: $_fdescdir"
134         debug "$_j procdir: $_procdir"
135         debug "$_j ruleset: $_ruleset"
136         debug "$_j fstab: $_fstab"
137
138         i=0
139         while : ; do
140                 eval out=\"\${_exec_prestart${i}:-''}\"
141                 if [ -z "$out" ]; then
142                         break
143                 fi
144                 debug "$_j exec pre-start #${i}: ${out}"
145                 i=$((i + 1))
146         done
147
148         debug "$_j exec start: $_exec_start"
149
150         i=1
151         while : ; do
152                 eval out=\"\${_exec_afterstart${i}:-''}\"
153
154                 if [ -z "$out" ]; then
155                         break;
156                 fi
157
158                 debug "$_j exec after start #${i}: ${out}"
159                 i=$((i + 1))
160         done
161
162         i=0
163         while : ; do
164                 eval out=\"\${_exec_poststart${i}:-''}\"
165                 if [ -z "$out" ]; then
166                         break
167                 fi
168                 debug "$_j exec post-start #${i}: ${out}"
169                 i=$((i + 1))
170         done
171
172         i=0
173         while : ; do
174                 eval out=\"\${_exec_prestop${i}:-''}\"
175                 if [ -z "$out" ]; then
176                         break
177                 fi
178                 debug "$_j exec pre-stop #${i}: ${out}"
179                 i=$((i + 1))
180         done
181
182         debug "$_j exec stop: $_exec_stop"
183
184         i=0
185         while : ; do
186                 eval out=\"\${_exec_poststop${i}:-''}\"
187                 if [ -z "$out" ]; then
188                         break
189                 fi
190                 debug "$_j exec post-stop #${i}: ${out}"
191                 i=$((i + 1))
192         done
193
194         debug "$_j flags: $_flags"
195         debug "$_j consolelog: $_consolelog"
196
197         if [ -z "${_hostname}" ]; then
198                 err 3 "$name: No hostname has been defined for ${_j}"
199         fi
200         if [ -z "${_rootdir}" ]; then
201                 err 3 "$name: No root directory has been defined for ${_j}"
202         fi
203 }
204
205 # set_sysctl rc_knob mib msg
206 #       If the mib sysctl is set according to what rc_knob
207 #       specifies, this function does nothing. However if
208 #       rc_knob is set differently than mib, then the mib
209 #       is set accordingly and msg is displayed followed by
210 #       an '=" sign and the word 'YES' or 'NO'.
211 #
212 set_sysctl()
213 {
214         _knob="$1"
215         _mib="$2"
216         _msg="$3"
217
218         _current=`${SYSCTL} -n $_mib 2>/dev/null`
219         if checkyesno $_knob ; then
220                 if [ "$_current" -ne 1 ]; then
221                         echo -n " ${_msg}=YES"
222                         ${SYSCTL} 1>/dev/null ${_mib}=1
223                 fi
224         else
225                 if [ "$_current" -ne 0 ]; then
226                         echo -n " ${_msg}=NO"
227                         ${SYSCTL} 1>/dev/null ${_mib}=0
228                 fi
229         fi
230 }
231
232 # is_current_mountpoint()
233 #       Is the directory mount point for a currently mounted file
234 #       system?
235 #
236 is_current_mountpoint()
237 {
238         local _dir _dir2
239
240         _dir=$1
241
242         _dir=`echo $_dir | sed -Ee 's#//+#/#g' -e 's#/$##'`
243         [ ! -d "${_dir}" ] && return 1
244         _dir2=`df ${_dir} | tail +2 | awk '{ print $6 }'`
245         [ "${_dir}" = "${_dir2}" ]
246         return $?
247 }
248
249 # is_symlinked_mountpoint()
250 #       Is a mount point, or any of its parent directories, a symlink?
251 #
252 is_symlinked_mountpoint()
253 {
254         local _dir
255
256         _dir=$1
257
258         [ -L "$_dir" ] && return 0
259         [ "$_dir" = "/" ] && return 1
260         is_symlinked_mountpoint `dirname $_dir`
261         return $?
262 }
263
264 # secure_umount
265 #       Try to unmount a mount point without being vulnerable to
266 #       symlink attacks.
267 #
268 secure_umount()
269 {
270         local _dir
271
272         _dir=$1
273
274         if is_current_mountpoint ${_dir}; then
275                 umount -f ${_dir} >/dev/null 2>&1
276         else
277                 debug "Nothing mounted on ${_dir} - not unmounting"
278         fi
279 }
280
281
282 # jail_umount_fs
283 #       This function unmounts certain special filesystems in the
284 #       currently selected jail. The caller must call the init_variables()
285 #       routine before calling this one.
286 #
287 jail_umount_fs()
288 {
289         local _device _mountpt _rest
290
291         if checkyesno _fdescfs; then
292                 if [ -d "${_fdescdir}" ] ; then
293                         secure_umount ${_fdescdir}
294                 fi
295         fi
296         if checkyesno _devfs; then
297                 if [ -d "${_devdir}" ] ; then
298                         secure_umount ${_devdir}
299                 fi
300         fi
301         if checkyesno _procfs; then
302                 if [ -d "${_procdir}" ] ; then
303                         secure_umount ${_procdir}
304                 fi
305         fi
306         if checkyesno _mount; then
307                 [ -f "${_fstab}" ] || warn "${_fstab} does not exist"
308                 tail -r ${_fstab} | while read _device _mountpt _rest; do
309                         case ":${_device}" in
310                         :#* | :)
311                                 continue
312                                 ;;
313                         esac
314                         secure_umount ${_mountpt}
315                 done
316         fi
317 }
318
319 # jail_mount_fstab()
320 #       Mount file systems from a per jail fstab while trying to
321 #       secure against symlink attacks at the mount points.
322 #
323 #       If we are certain we cannot secure against symlink attacks we
324 #       do not mount all of the file systems (since we cannot just not
325 #       mount the file system with the problematic mount point).
326 #
327 #       The caller must call the init_variables() routine before
328 #       calling this one.
329 #
330 jail_mount_fstab()
331 {
332         local _device _mountpt _rest
333
334         while read _device _mountpt _rest; do
335                 case ":${_device}" in
336                 :#* | :)
337                         continue
338                         ;;
339                 esac
340                 if is_symlinked_mountpoint ${_mountpt}; then
341                         warn "${_mountpt} has symlink as parent - not mounting from ${_fstab}"
342                         return
343                 fi
344         done <${_fstab}
345         mount -a -F "${_fstab}"
346 }
347
348 # jail_show_addresses jail
349 #       Debug print the input for the given _multi aliases
350 #       for a jail for init_variables().
351 #
352 jail_show_addresses()
353 {
354         local _j _type alias
355         _j="$1"
356         alias=0
357
358         if [ -z "${_j}" ]; then
359                 warn "jail_show_addresses: you must specify a jail"
360                 return
361         fi
362
363         while : ; do
364                 eval _addr=\"\$jail_${_j}_ip_multi${alias}\"
365                 if [ -n "${_addr}" ]; then
366                         debug "${_j} ip_multi${alias}: $_addr"
367                         alias=$((${alias} + 1))
368                 else
369                         break
370                 fi
371         done
372 }
373
374 # jail_extract_address argument
375 #       The second argument is the string from one of the _ip
376 #       or the _multi variables. In case of a comma separated list
377 #       only one argument must be passed in at a time.
378 #       The function alters the _type, _iface, _addr and _mask variables.
379 #
380 jail_extract_address()
381 {
382         local _i
383         _i=$1
384
385         if [ -z "${_i}" ]; then
386                 warn "jail_extract_address: called without input"
387                 return
388         fi
389
390         # Check if we have an interface prefix given and split into
391         # iFace and rest.
392         case "${_i}" in
393         *\|*)   # ifN|.. prefix there
394                 _iface=${_i%%|*}
395                 _r=${_i##*|}
396                 ;;
397         *)      _iface=""
398                 _r=${_i}
399                 ;;
400         esac
401
402         # In case the IP has no interface given, check if we have a global one.
403         _iface=${_iface:-${_interface}}
404
405         # Set address, cut off any prefix/netmask/prefixlen.
406         _addr=${_r}
407         _addr=${_addr%%[/ ]*}
408
409         # Theoretically we can return here if interface is not set,
410         # as we only care about the _mask if we call ifconfig.
411         # This is not done because we may want to santize IP addresses
412         # based on _type later, and optionally change the type as well.
413
414         # Extract the prefix/netmask/prefixlen part by cutting off the address.
415         _mask=${_r}
416         _mask=`expr "${_mask}" : "${_addr}\(.*\)"`
417
418         # Identify type {inet,inet6}.
419         case "${_addr}" in
420         *\.*\.*\.*)     _type="inet" ;;
421         *:*)            _type="inet6" ;;
422         *)              warn "jail_extract_address: type not identified"
423                         ;;
424         esac
425
426         # Handle the special /netmask instead of /prefix or
427         # "netmask xxx" case for legacy IP.
428         # We do NOT support shortend class-full netmasks.
429         if [ "${_type}" = "inet" ]; then
430                 case "${_mask}" in
431                 /*\.*\.*\.*)    _mask=" netmask ${_mask#/}" ;;
432                 *)              ;;
433                 esac
434
435                 # In case _mask is still not set use /32.
436                 _mask=${_mask:-/32}
437
438         elif [ "${_type}" = "inet6" ]; then
439                 # In case _maske is not set for IPv6, use /128.
440                 _mask=${_mask:-/128}
441         fi
442 }
443
444 # jail_handle_ips_option {add,del} input
445 #       Handle a single argument imput which can be a comma separated
446 #       list of addresses (theoretically with an option interface and
447 #       prefix/netmask/prefixlen).
448 #
449 jail_handle_ips_option()
450 {
451         local _x _action _type _i
452         _action=$1
453         _x=$2
454
455         if [ -z "${_x}" ]; then
456                 # No IP given. This can happen for the primary address
457                 # of each address family.
458                 return
459         fi
460
461         # Loop, in case we find a comma separated list, we need to handle
462         # each argument on its own.
463         while [ ${#_x} -gt 0 ]; do
464                 case "${_x}" in
465                 *,*)    # Extract the first argument and strip it off the list.
466                         _i=`expr "${_x}" : '^\([^,]*\)'`
467                         _x=`expr "${_x}" : "^[^,]*,\(.*\)"`
468                         ;;
469                 *)      _i=${_x}
470                         _x=""
471                         ;;
472                 esac
473
474                 _type=""
475                 _iface=""
476                 _addr=""
477                 _mask=""
478                 jail_extract_address "${_i}"
479
480                 # make sure we got an address.
481                 case "${_addr}" in
482                 "")     continue ;;
483                 *)      ;;
484                 esac
485
486                 # Append address to list of addresses for the jail command.
487                 case "${_addrl}" in
488                 "")     _addrl="${_addr}" ;;
489                 *)      _addrl="${_addrl},${_addr}" ;;
490                 esac
491
492                 # Configure interface alias if requested by a given interface
493                 # and if we could correctly parse everything.
494                 case "${_iface}" in
495                 "")     continue ;;
496                 esac
497                 case "${_type}" in
498                 inet)   ;;
499                 inet6)  ;;
500                 *)      warn "Could not determine address family.  Not going" \
501                             "to ${_action} address '${_addr}' for ${_jail}."
502                         continue
503                         ;;
504                 esac
505                 case "${_action}" in
506                 add)    ifconfig ${_iface} ${_type} ${_addr}${_mask} alias
507                         ;;
508                 del)    # When removing the IP, ignore the _mask.
509                         ifconfig ${_iface} ${_type} ${_addr} -alias
510                         ;;
511                 esac
512         done
513 }
514
515 # jail_ips {add,del}
516 #       Extract the comma separated list of addresses and return them
517 #       for the jail command.
518 #       Handle more than one address via the _multi option as well.
519 #       If an interface is given also add/remove an alias for the
520 #       address with an optional netmask.
521 #
522 jail_ips()
523 {
524         local _action
525         _action=$1
526
527         case "${_action}" in
528         add)    ;;
529         del)    ;;
530         *)      warn "jail_ips: invalid action '${_action}'"
531                 return
532                 ;;
533         esac
534
535         # Handle addresses.
536         jail_handle_ips_option ${_action} "${_ip}"
537         # Handle jail_xxx_ip_multi<N>
538         alias=0
539         while : ; do
540                 eval _x=\"\$jail_${_jail}_ip_multi${alias}\"
541                 case "${_x}" in
542                 "")     break ;;
543                 *)      jail_handle_ips_option ${_action} "${_x}"
544                         alias=$((${alias} + 1))
545                         ;;
546                 esac
547         done
548 }
549
550 jail_prestart()
551 {
552         if checkyesno jail_parallel_start; then
553                 command_args='&'
554         fi
555 }
556
557 jail_start()
558 {
559         echo -n 'Configuring jails:'
560         set_sysctl jail_set_hostname_allow security.jail.set_hostname_allowed \
561             set_hostname_allow
562         set_sysctl jail_socket_unixiproute_only \
563             security.jail.socket_unixiproute_only unixiproute_only
564         set_sysctl jail_sysvipc_allow security.jail.sysvipc_allowed \
565             sysvipc_allow
566         echo '.'
567
568         echo -n 'Starting jails:'
569         _tmp_dir=`mktemp -d /tmp/jail.XXXXXXXX` || \
570             err 3 "$name: Can't create temp dir, exiting..."
571         for _jail in ${jail_list}
572         do
573                 init_variables $_jail
574                 if [ -f /var/run/jail_${_jail}.id ]; then
575                         echo -n " [${_hostname} already running (/var/run/jail_${_jail}.id exists)]"
576                         continue;
577                 fi
578                 _addrl=""
579                 jail_ips "add"
580                 if [ -n "${_fib}" ]; then
581                         _setfib="setfib -F '${_fib}'"
582                 else
583                         _setfib=""
584                 fi
585                 if checkyesno _mount; then
586                         info "Mounting fstab for jail ${_jail} (${_fstab})"
587                         if [ ! -f "${_fstab}" ]; then
588                                 err 3 "$name: ${_fstab} does not exist"
589                         fi
590                         jail_mount_fstab
591                 fi
592                 if checkyesno _devfs; then
593                         # If devfs is already mounted here, skip it.
594                         df -t devfs "${_devdir}" >/dev/null
595                         if [ $? -ne 0 ]; then
596                                 if is_symlinked_mountpoint ${_devdir}; then
597                                         warn "${_devdir} has symlink as parent - not starting jail ${_jail}"
598                                         continue
599                                 fi
600                                 info "Mounting devfs on ${_devdir}"
601                                 devfs_mount_jail "${_devdir}" ${_ruleset}
602                                 # Transitional symlink for old binaries
603                                 if [ ! -L "${_devdir}/log" ]; then
604                                         __pwd="`pwd`"
605                                         cd "${_devdir}"
606                                         ln -sf ../var/run/log log
607                                         cd "$__pwd"
608                                 fi
609                         fi
610
611                         # XXX - It seems symlinks don't work when there
612                         #       is a devfs(5) device of the same name.
613                         # Jail console output
614                         #       __pwd="`pwd`"
615                         #       cd "${_devdir}"
616                         #       ln -sf ../var/log/console console
617                         #       cd "$__pwd"
618                 fi
619                 if checkyesno _fdescfs; then
620                         if is_symlinked_mountpoint ${_fdescdir}; then
621                                 warn "${_fdescdir} has symlink as parent, not mounting"
622                         else
623                                 info "Mounting fdescfs on ${_fdescdir}"
624                                 mount -t fdescfs fdesc "${_fdescdir}"
625                         fi
626                 fi
627                 if checkyesno _procfs; then
628                         if is_symlinked_mountpoint ${_procdir}; then
629                                 warn "${_procdir} has symlink as parent, not mounting"
630                         else
631                                 info "Mounting procfs onto ${_procdir}"
632                                 if [ -d "${_procdir}" ] ; then
633                                         mount -t procfs proc "${_procdir}"
634                                 fi
635                         fi
636                 fi
637                 _tmp_jail=${_tmp_dir}/jail.$$
638
639                 i=0
640                 while : ; do
641                         eval out=\"\${_exec_prestart${i}:-''}\"
642                         [ -z "$out" ] && break
643                         ${out}
644                         i=$((i + 1))
645                 done
646
647                 eval ${_setfib} jail ${_flags} -i ${_rootdir} ${_hostname} \
648                         \"${_addrl}\" ${_exec_start} > ${_tmp_jail} 2>&1 \
649                         </dev/null
650
651                 if [ "$?" -eq 0 ] ; then
652                         _jail_id=$(head -1 ${_tmp_jail})
653                         i=1
654                         while : ; do
655                                 eval out=\"\${_exec_afterstart${i}:-''}\"
656
657                                 if [ -z "$out" ]; then
658                                         break;
659                                 fi
660
661                                 jexec "${_jail_id}" ${out}
662                                 i=$((i + 1))
663                         done
664
665                         echo -n " $_hostname"
666                         tail +2 ${_tmp_jail} >${_consolelog}
667                         echo ${_jail_id} > /var/run/jail_${_jail}.id
668
669                         i=0
670                         while : ; do
671                                 eval out=\"\${_exec_poststart${i}:-''}\"
672                                 [ -z "$out" ] && break
673                                 ${out}
674                                 i=$((i + 1))
675                         done
676                 else
677                         jail_umount_fs
678                         jail_ips "del"
679                         echo " cannot start jail \"${_jail}\": "
680                         tail +2 ${_tmp_jail}
681                 fi
682                 rm -f ${_tmp_jail}
683         done
684         rmdir ${_tmp_dir}
685         echo '.'
686 }
687
688 jail_stop()
689 {
690         echo -n 'Stopping jails:'
691         for _jail in ${jail_list}
692         do
693                 if [ -f "/var/run/jail_${_jail}.id" ]; then
694                         _jail_id=$(cat /var/run/jail_${_jail}.id)
695                         if [ ! -z "${_jail_id}" ]; then
696                                 init_variables $_jail
697
698                                 i=0
699                                 while : ; do
700                                         eval out=\"\${_exec_prestop${i}:-''}\"
701                                         [ -z "$out" ] && break
702                                         ${out}
703                                         i=$((i + 1))
704                                 done
705
706                                 if [ -n "${_exec_stop}" ]; then
707                                         eval env -i /usr/sbin/jexec ${_jail_id} ${_exec_stop} \
708                                                 >> ${_consolelog} 2>&1
709                                 fi
710                                 killall -j ${_jail_id} -TERM > /dev/null 2>&1
711                                 sleep 1
712                                 killall -j ${_jail_id} -KILL > /dev/null 2>&1
713                                 jail_umount_fs
714                                 echo -n " $_hostname"
715
716                                 i=0
717                                 while : ; do
718                                         eval out=\"\${_exec_poststop${i}:-''}\"
719                                         [ -z "$out" ] && break
720                                         ${out}
721                                         i=$((i + 1))
722                                 done
723                         fi
724                         jail_ips "del"
725                         rm /var/run/jail_${_jail}.id
726                 else
727                         echo " cannot stop jail ${_jail}. No jail id in /var/run"
728                 fi
729         done
730         echo '.'
731 }
732
733 load_rc_config $name
734 cmd="$1"
735 if [ $# -gt 0 ]; then
736         shift
737 fi
738 if [ -n "$*" ]; then
739         jail_list="$*"
740 fi
741
742 run_rc_command "${cmd}"