6d1fcb0916
- Resolve issue on systems set to UTC time would fail copying /etc/localtime to the chroot [2] PR: ports/162447 [1] Submitted by: Hilko Meyer <hilko.meyer@gmx.de> [1] Reported by: dougb@ [2] Feature safe: yes
526 lines
12 KiB
Bash
526 lines
12 KiB
Bash
#! /bin/sh
|
|
#
|
|
# $FreeBSD$
|
|
#
|
|
# PROVIDE: dhcpd
|
|
# REQUIRE: DAEMON
|
|
# BEFORE: LOGIN
|
|
# KEYWORD: shutdown
|
|
#
|
|
# Add the following line to /etc/rc.conf to enable dhcpd:
|
|
#
|
|
# dhcpd_enable="YES"
|
|
|
|
. /etc/rc.subr
|
|
|
|
case $0 in
|
|
/etc/rc*)
|
|
# during boot (shutdown) $0 is /etc/rc (/etc/rc.shutdown),
|
|
# so get the name of the script from $_file
|
|
name=$_file
|
|
;;
|
|
*)
|
|
name=$0
|
|
;;
|
|
esac
|
|
|
|
name=${name##*/isc-}
|
|
paranoia=%%PARANOIA%% # compiled in paranoia?
|
|
|
|
load_rc_config ${name}
|
|
|
|
# override these variables in /etc/rc.conf
|
|
eval ": \${${name}_enable:=\"NO\"}"
|
|
# dhcpd_flags="" # -q -early_chroot # command option(s)
|
|
# dhcpd_ifaces="" # ethernet interface(s)
|
|
eval ": \${${name}_conf:=%%PREFIX%%/etc/${name}.conf}" # configuration file
|
|
eval ": \${${name}_withumask:=022}" # file creation mask
|
|
|
|
eval ": \${${name}_chuser_enable:=\"%%PARANOIA%%\"}" # runs w/o privileges?
|
|
eval ": \${${name}_withuser:=dhcpd}" # user name to run as
|
|
eval ": \${${name}_withgroup:=dhcpd}" # group name to run as
|
|
|
|
eval ": \${${name}_chroot_enable:=\"NO\"}" # runs chrooted?
|
|
eval ": \${${name}_devfs_enable:=\"YES\"}" # devfs if available?
|
|
eval ": \${${name}_rootdir:=/var/db/${name}}" # directory to run in
|
|
# dhcpd_includedir="" # directory for included config files
|
|
|
|
safe_run () # rc command [args...]
|
|
{
|
|
local _rc
|
|
|
|
_rc=$1
|
|
shift
|
|
|
|
if [ "${_rc}" -eq 0 ]; then
|
|
debug safe_run: "$@"
|
|
"$@" || _rc=1
|
|
else
|
|
warn safe_run: "$@"
|
|
fi
|
|
return ${_rc}
|
|
}
|
|
|
|
precious () # entry...
|
|
{
|
|
local _entry _rc
|
|
|
|
_rc=0
|
|
for _entry; do
|
|
# do nothing if /dev, /var/run or /var/db
|
|
echo ${_entry} | egrep -q '^//*(dev|var//*(run|db))?/*$' || _rc=1
|
|
done
|
|
debug precious: "$@" rc=${_rc}
|
|
return ${_rc}
|
|
}
|
|
|
|
lsmod () # user group file...
|
|
{
|
|
local _entry _user _group _rc
|
|
|
|
_user=$1 _group=$2
|
|
shift 2
|
|
|
|
_rc=0
|
|
for _entry; do
|
|
ls -ld ${_entry} 2> /dev/null |
|
|
awk -v u=${_user} -v g=${_group} '{
|
|
exit ((u && $3 != u) || (g && $4 != g))
|
|
}' || _rc=1
|
|
done
|
|
debug lsmod: "$@" rc=${_rc}
|
|
return ${_rc}
|
|
}
|
|
|
|
safe_chmog () # entry...
|
|
{
|
|
local _entry _user _group _usergroup _rc
|
|
|
|
eval "_user=\${${name}_withuser}"
|
|
eval "_group=\${${name}_withgroup}"
|
|
|
|
_rc=0
|
|
if [ -n "${_user}" -o -n "${_group}" ]; then
|
|
_usergroup=${_user}${_group:+:${_group}}
|
|
for _entry; do
|
|
if [ -d ${_entry} ] && mounted ${_entry}; then
|
|
continue
|
|
fi
|
|
if [ -e ${_entry} ] &&
|
|
! precious ${_entry} &&
|
|
! lsmod ${_user} ${_group} ${_entry} &&
|
|
! safe_run ${_rc} chown ${_usergroup} ${_entry}; then
|
|
warn "unable to change permissions of ${_entry}"
|
|
_rc=1
|
|
fi
|
|
done
|
|
fi
|
|
return ${_rc}
|
|
}
|
|
|
|
safe_mkdir () # dir...
|
|
{
|
|
local _dir _rc
|
|
|
|
_rc=0
|
|
for _dir; do
|
|
if [ ! -d ${_dir} ] &&
|
|
! precious ${_dir} &&
|
|
! safe_run ${_rc} mkdir -p ${_dir}; then
|
|
err 1 "unable to create directory ${_dir}"
|
|
_rc=1
|
|
fi
|
|
done
|
|
safe_run ${_rc} safe_chmog "$@" || _rc=1
|
|
return ${_rc}
|
|
}
|
|
|
|
safe_rmdir () # dir...
|
|
{
|
|
local _dir _rc
|
|
|
|
_rc=0
|
|
for _dir; do
|
|
if [ -d ${_dir} ] &&
|
|
! precious ${_dir} &&
|
|
! mounted ${_dir}; then
|
|
if safe_run ${_rc} rmdir ${_dir}; then
|
|
safe_run ${_rc} safe_rmdir ${_dir%/*} || _rc=1
|
|
else
|
|
warn "unable to remove directory ${_dir}"
|
|
_rc=1
|
|
fi
|
|
fi
|
|
done
|
|
return ${_rc}
|
|
}
|
|
|
|
safe_touch () # file...
|
|
{
|
|
local _file _rc
|
|
|
|
_rc=0
|
|
for _file; do
|
|
if [ ! -e ${_file} ] &&
|
|
! safe_run ${_rc} touch ${_file}; then
|
|
err 1 "unable to create file ${_file}"
|
|
_rc=1
|
|
fi
|
|
done
|
|
safe_run ${_rc} safe_chmog "$@" || _rc=1
|
|
return ${_rc}
|
|
}
|
|
|
|
safe_remove () # entry...
|
|
{
|
|
local _entry _rc
|
|
|
|
_rc=0
|
|
for _entry; do
|
|
if [ -f ${_entry} ]; then
|
|
if ! safe_run ${_rc} rm -f ${_entry}; then
|
|
warn "unable to remove file ${_entry}"
|
|
_rc=1
|
|
fi
|
|
elif [ -d ${_entry} ] &&
|
|
! precious ${_entry} &&
|
|
! mounted ${_entry}; then
|
|
if ! safe_run ${_rc} rm -rf ${_entry}; then
|
|
warn "unable to remove directory ${_entry}"
|
|
_rc=1
|
|
fi
|
|
fi
|
|
done
|
|
return ${_rc}
|
|
}
|
|
|
|
safe_copy () # src dst
|
|
{
|
|
local _src _dst _rc
|
|
|
|
_src=$1 _dst=$2
|
|
|
|
_rc=0
|
|
if [ -f ${_src} ]; then
|
|
if ! safe_run ${_rc} safe_remove ${_dst} ||
|
|
! safe_run ${_rc} cp -p ${_src} ${_dst}; then
|
|
err 1 "unable to copy file ${_src} to ${_dst}"
|
|
_rc=1
|
|
fi
|
|
safe_run ${_rc} safe_chmog ${_dst} || _rc=1
|
|
elif [ -d ${_src} ] &&
|
|
! precious ${_dst} &&
|
|
! mounted ${_dst}; then
|
|
if ! safe_run ${_rc} pax -rw -pe -ts "|^${_src}||" \
|
|
${_src} ${_dst}; then
|
|
err 1 "unable to copy directory ${_src} to ${_dst}"
|
|
_rc=1
|
|
fi
|
|
else
|
|
err 1 "unable to copy ${_src} to ${_dst}" \
|
|
"-- not a file or a directory"
|
|
_rc=1
|
|
fi
|
|
return ${_rc}
|
|
}
|
|
|
|
mounted () # dir...
|
|
{
|
|
local _rc
|
|
|
|
_rc=1
|
|
if checkyesno ${name}_devfs_enable; then
|
|
mount -t devfs | awk '
|
|
BEGIN { n = ARGC; ARGC = 2 }
|
|
{ for (i = 2; i != n; i++) if ($3 == ARGV[i]) exit 1 }
|
|
' - "$@" || _rc=0
|
|
fi
|
|
debug mounted: "$@" rc=${_rc}
|
|
return ${_rc}
|
|
}
|
|
|
|
safe_mount () # dir
|
|
{
|
|
local _dir _rc
|
|
|
|
_dir=$1
|
|
|
|
_rc=0
|
|
if checkyesno ${name}_devfs_enable &&
|
|
! mounted ${_dir} &&
|
|
! safe_run ${_rc} mount -t devfs devfs ${_dir}; then
|
|
err 1 "unable to mount ${_dir}"
|
|
_rc=1
|
|
fi
|
|
return ${_rc}
|
|
}
|
|
|
|
safe_umount () # dir
|
|
{
|
|
local _dir _rc
|
|
|
|
_dir=$1
|
|
|
|
_rc=0
|
|
if checkyesno ${name}_devfs_enable &&
|
|
mounted ${_dir} &&
|
|
! safe_run ${_rc} umount ${_dir}; then
|
|
warn "unable to unmount ${_dir}"
|
|
_rc=1
|
|
fi
|
|
return ${_rc}
|
|
}
|
|
|
|
check_chuser ()
|
|
{
|
|
if checkyesno paranoia; then
|
|
if checkyesno ${name}_chuser_enable &&
|
|
eval "[ -z \"\${${name}_withuser}\" -a -z \"\${${name}_withgroup}\" ]"; then
|
|
err 1 "one of ${name}_withuser and ${name}_withgroup" \
|
|
"must be set if ${name}_chuser_enable is enabled"
|
|
fi
|
|
else
|
|
if checkyesno ${name}_chuser_enable; then
|
|
warn "${name}_chuser_enable disabled -- not compiled in"
|
|
eval "${name}_chuser_enable=NO"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
check_chroot ()
|
|
{
|
|
if checkyesno paranoia; then
|
|
if checkyesno ${name}_chroot_enable; then
|
|
if eval "[ -z \"\${${name}_rootdir}\" ]"; then
|
|
err 1 "${name}_rootdir must be set" \
|
|
"if ${name}_chroot_enable is enabled"
|
|
fi
|
|
else
|
|
eval "${name}_devfs_enable=NO"
|
|
fi
|
|
else
|
|
if checkyesno ${name}_chroot_enable; then
|
|
warn "${name}_chroot_enable disabled -- not compiled in"
|
|
eval "${name}_chroot_enable=NO"
|
|
fi
|
|
eval "${name}_devfs_enable=NO"
|
|
fi
|
|
}
|
|
|
|
rcvar_chuser ()
|
|
{
|
|
if checkyesno paranoia && checkyesno ${name}_chuser_enable; then
|
|
eval "${name}_piddir=\${__dhcpd_piddir}/\${name}"
|
|
eval "${name}_leasesdir=\${__dhcpd_leasesdir}/\${name}"
|
|
else
|
|
eval unset "${name}_withuser= ${name}_withgroup="
|
|
fi
|
|
}
|
|
|
|
rcvar_chroot ()
|
|
{
|
|
if ! checkyesno paranoia || ! checkyesno ${name}_chroot_enable; then
|
|
eval "${name}_rootdir="
|
|
elif checkyesno paranoia && checkyesno ${name}_chroot_enable; then
|
|
eval "${name}_devdir=\${__dhcpd_devdir}"
|
|
eval "${name}_etcdir=\${__dhcpd_etcdir}"
|
|
fi
|
|
}
|
|
|
|
rcvar_pidnleases ()
|
|
{
|
|
if ! checkyesno ${name}_chuser_enable; then
|
|
eval "${name}_piddir=\${__dhcpd_piddir}"
|
|
eval "${name}_leasesdir=\${__dhcpd_leasesdir}"
|
|
fi
|
|
eval "${name}_pidfile=\${${name}_piddir}/\${name}.pid"
|
|
eval "${name}_leasesfile=\${${name}_leasesdir}/\${name}.leases"
|
|
eval "${name}_conffile=\${${name}_conf}" # for convenience only
|
|
eval "${name}_confdir=\$(dirname \${${name}_conffile})"
|
|
}
|
|
|
|
rcvar_rooted ()
|
|
{
|
|
eval "_dhcpd_rootdir=\${${name}_rootdir}"
|
|
eval "_dhcpd_devdir=\${${name}_rootdir}\${${name}_devdir}"
|
|
eval "_dhcpd_etcdir=\${${name}_rootdir}\${${name}_etcdir}"
|
|
eval "_dhcpd_confdir=\${${name}_rootdir}\${${name}_confdir}"
|
|
eval "_dhcpd_includedir=\${${name}_rootdir}\${${name}_includedir}"
|
|
eval "_dhcpd_piddir=\${${name}_rootdir}\${${name}_piddir}"
|
|
eval "_dhcpd_leasesdir=\${${name}_rootdir}\${${name}_leasesdir}"
|
|
eval "_dhcpd_conffile=\${${name}_rootdir}\${${name}_conffile}"
|
|
eval "_dhcpd_pidfile=\${${name}_rootdir}\${${name}_pidfile}"
|
|
eval "_dhcpd_leasesfile=\${${name}_rootdir}\${${name}_leasesfile}"
|
|
}
|
|
|
|
setup_umask ()
|
|
{
|
|
if eval "[ -n \"\${${name}_withumask}\" ]"; then
|
|
eval "umask \${${name}_withumask}"
|
|
fi
|
|
}
|
|
|
|
setup_chroot ()
|
|
{
|
|
local _hconf _hosts _ltime _rconf
|
|
|
|
_hconf=host.conf
|
|
_hosts=hosts
|
|
_ltime=localtime
|
|
_rconf=resolv.conf
|
|
|
|
if checkyesno paranoia && checkyesno ${name}_chroot_enable; then
|
|
if ! mounted ${_dhcpd_devdir}; then
|
|
safe_mkdir ${_dhcpd_devdir}/_
|
|
# XXX /_ hack! so, .../dev is root owned.
|
|
fi
|
|
safe_mkdir ${_dhcpd_rootdir} ${_dhcpd_etcdir}/_ ${_dhcpd_confdir}
|
|
# XXX /_ hack! so, .../etc is root owned.
|
|
if checkyesno ${name}_devfs_enable; then
|
|
safe_mount ${_dhcpd_devdir}
|
|
else
|
|
eval "safe_copy \${${name}_devdir} \${_dhcpd_devdir}"
|
|
fi
|
|
eval "safe_copy \${${name}_conffile} \${_dhcpd_conffile}"
|
|
eval "safe_copy \${${name}_etcdir}/\$_hconf \${_dhcpd_etcdir}/\$_hconf"
|
|
eval "safe_copy \${${name}_etcdir}/\$_hosts \${_dhcpd_etcdir}/\$_hosts"
|
|
# copy localtime only if it exists
|
|
if eval "[ -f \"\${${name}_etcdir}/\$_ltime\" ]"; then
|
|
eval "safe_copy \${${name}_etcdir}/\$_ltime \${_dhcpd_etcdir}/\$_ltime"
|
|
fi
|
|
eval "safe_copy \${${name}_etcdir}/\$_rconf \${_dhcpd_etcdir}/\$_rconf"
|
|
# copy dhcpd_includedir if defined and available
|
|
if eval "[ -d \"\${${name}_includedir}\" ]"; then
|
|
safe_mkdir ${_dhcpd_includedir}
|
|
eval "safe_copy \${${name}_includedir} \${_dhcpd_includedir}"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
setup_chuser ()
|
|
{
|
|
if checkyesno paranoia && {
|
|
checkyesno ${name}_chuser_enable || checkyesno ${name}_chroot_enable
|
|
}; then
|
|
safe_mkdir ${_dhcpd_piddir} ${_dhcpd_leasesdir}
|
|
fi
|
|
}
|
|
|
|
setup_leases ()
|
|
{
|
|
safe_touch ${_dhcpd_leasesfile}
|
|
}
|
|
|
|
setup_flags ()
|
|
{
|
|
if [ "${name}" = "dhcpd6" ]; then
|
|
rc_flags="${rc_flags} -6"
|
|
fi
|
|
if eval "[ -n \"\${${name}_conf}\" ]"; then
|
|
eval "rc_flags=\"\${rc_flags} -cf \${${name}_conf}\""
|
|
fi
|
|
if eval "[ -n \"\${${name}_leasesfile}\" ]"; then
|
|
eval "rc_flags=\"\${rc_flags} -lf \${${name}_leasesfile}\""
|
|
fi
|
|
if eval "[ -n \"\${${name}_pidfile}\" ]"; then
|
|
eval "rc_flags=\"\${rc_flags} -pf \${${name}_pidfile}\""
|
|
fi
|
|
if eval "[ -n \"\${${name}_withuser}\" ]"; then
|
|
eval "rc_flags=\"\${rc_flags} -user \${${name}_withuser}\""
|
|
fi
|
|
if eval "[ -n \"\${${name}_withgroup}\" ]"; then
|
|
eval "rc_flags=\"\${rc_flags} -group \${${name}_withgroup}\""
|
|
fi
|
|
if eval "[ -n \"\${${name}_rootdir}\" ]"; then
|
|
eval "rc_flags=\"\${rc_flags} -chroot \${${name}_rootdir}\""
|
|
fi
|
|
eval "rc_flags=\"\${rc_flags} \${${name}_ifaces}\""
|
|
}
|
|
|
|
cleanup_chroot ()
|
|
{
|
|
if checkyesno paranoia && checkyesno ${name}_chroot_enable; then
|
|
safe_umount ${_dhcpd_devdir}
|
|
fi
|
|
}
|
|
|
|
dhcpd_stop ()
|
|
{
|
|
if sh $0 forcestatus; then
|
|
sh $0 forcestop
|
|
fi
|
|
}
|
|
|
|
dhcpd_check ()
|
|
{
|
|
check_chuser
|
|
check_chroot
|
|
}
|
|
|
|
dhcpd_rcvar ()
|
|
{
|
|
rcvar_chuser
|
|
rcvar_chroot
|
|
rcvar_pidnleases
|
|
rcvar_rooted
|
|
}
|
|
|
|
dhcpd_precmd ()
|
|
{
|
|
setup_umask
|
|
setup_chroot
|
|
setup_chuser
|
|
setup_leases
|
|
setup_flags
|
|
}
|
|
|
|
dhcpd_postcmd ()
|
|
{
|
|
cleanup_chroot
|
|
}
|
|
|
|
dhcpd_restartprecmd ()
|
|
{
|
|
setup_chroot
|
|
setup_flags
|
|
dhcpd_checkconfig
|
|
}
|
|
|
|
dhcpd_checkconfig ()
|
|
{
|
|
local rc_flags_mod
|
|
setup_flags
|
|
rc_flags_mod="$rc_flags"
|
|
# Eliminate '-q' flag if it is present
|
|
case "$rc_flags" in
|
|
*-q*) rc_flags_mod=`echo "${rc_flags}" | sed -Ee 's/(^-q | -q | -q$)//'` ;;
|
|
esac
|
|
if ! ${command} -t -q ${rc_flags_mod}; then
|
|
err 1 "`${command} -t ${rc_flags_mod}` Configuration file sanity check failed"
|
|
fi
|
|
}
|
|
|
|
rcvar=${name}_enable
|
|
load_rc_config ${name}
|
|
|
|
__dhcpd_uninstall="NO" # internal use only
|
|
__dhcpd_devdir=/dev # devices directory
|
|
__dhcpd_etcdir=/etc # etc directory
|
|
__dhcpd_piddir=/var/run # pid file directory
|
|
__dhcpd_leasesdir=/var/db # leases file directory
|
|
#__dhcpd_rootdir=/var/db/${name} # root directory
|
|
|
|
dhcpd_check
|
|
dhcpd_rcvar
|
|
|
|
command=%%PREFIX%%/sbin/dhcpd
|
|
pidfile=${_dhcpd_pidfile}
|
|
eval "required_files=\${${name}_conf}"
|
|
start_precmd=dhcpd_precmd
|
|
stop_postcmd=dhcpd_postcmd
|
|
restart_precmd="dhcpd_restartprecmd"
|
|
uninstall_cmd=dhcpd_uninstall
|
|
configtest_cmd="dhcpd_restartprecmd"
|
|
extra_commands="uninstall configtest"
|
|
|
|
run_rc_command "$1"
|