#	$OpenBSD: rc,v 1.438 2014/08/04 20:17:09 naddy Exp $

# System startup script run by init on autoboot
# or after single-user.
# Output and error are redirected to console by init,
# and the console is the controlling terminal.

# Subroutines (have to come first).

# Strip comments (and leading/trailing whitespace if IFS is set)
# from a file and spew to stdout
stripcom() {
	local _file="$1"
	local _line

	{
		while read _line ; do
			_line=${_line%%#*}		# strip comments
			test -z "$_line" && continue
			echo $_line
		done
	} < $_file
}

# Update resource limits when sysctl changes
# Usage: update_limit -X loginconf_name
update_limit() {
	local _fl="$1"	# ulimit flag
	local _lc="$2"	# login.conf name
	local _new _suf

	for _suf in "" -cur -max; do
		_new=`getcap -f /etc/login.conf -s ${_lc}${_suf} daemon 2>/dev/null`
		if [ X"$_new" != X"" ]; then
			if [ X"$_new" = X"infinity" ]; then
				_new=unlimited
			fi
			case "$_suf" in
			-cur)
				ulimit -S $_fl $_new
				;;
			-max)
				ulimit -H $_fl $_new
				;;
			*)
				ulimit $_fl $_new
				return
				;;
			esac
		fi
	done
}

sysctl_conf() {
	test -s /etc/sysctl.conf || return

	# delete comments and blank lines
	set -- `stripcom /etc/sysctl.conf`
	while [ $# -ge 1 ] ; do
		sysctl $1
		# update limits if needed
		case $1 in
		kern.maxproc=*)
			update_limit -p maxproc
			;;
		kern.maxfiles=*)
			update_limit -n openfiles
			;;
		esac
		shift
	done
}

mixerctl_conf()
{
	test -s /etc/mixerctl.conf || return

	# delete comments and blank lines
	set -- `stripcom /etc/mixerctl.conf`
	while [ $# -ge 1 ] ; do
		mixerctl -q $1 > /dev/null 2>&1
		shift
	done
}

wsconsctl_conf()
{
	local save_IFS="$IFS"

	test -x /sbin/wsconsctl -a -s /etc/wsconsctl.conf || return
	# delete comments and blank lines
	IFS="
"
	set -- `stripcom /etc/wsconsctl.conf`
	IFS="$save_IFS"
	while [ $# -ge 1 ] ; do
		eval wsconsctl $1
		shift
	done
}

random_seed()
{
	# push the old seed into the kernel
	dd if=/var/db/host.random of=/dev/random bs=65536 count=1 status=none
	chmod 600 /var/db/host.random
	# ... and create a future seed
	dd if=/dev/random of=/var/db/host.random bs=65536 count=1 status=none
	# and create a seed file for the boot-loader
	dd if=/dev/random of=/etc/random.seed bs=512 count=1 status=none
	chmod 600 /etc/random.seed
}

fill_baddynamic()
{
	local _service=$1
	local _sysctl="net.inet.${_service}.baddynamic"
	stripcom /etc/services |
	{
		# Variables are local
		while IFS=" 	/" read _name _port _srv _junk; do
			[ "x${_srv}" = "x${_service}" ] || continue
			_ban="${_ban:+${_ban},}+${_port}"
			# Flush before argv gets too long
			if [ ${#_ban} -gt 1024 ]; then
				sysctl -q ${_sysctl}=${_ban}
				_ban=""
			fi
		done
		[ "${_ban}" ] && sysctl -q ${_sysctl}=${_ban}
	}
}

start_daemon()
{
	local _n
	for _n; do
		eval _do=\${${_n}_flags}
		if [ X"${_do}" != X"NO" ]; then
			/etc/rc.d/${_n} start
		fi
	done
}

make_keys()
{
	if [ X"${named_flags}" != X"NO" ]; then
		if ! cmp -s /etc/rndc.key /var/named/etc/rndc.key ; then
			echo -n "rndc-confgen: generating shared secret... "
			if rndc-confgen -a -t /var/named >/dev/null 2>&1; then
				chmod 0640 /var/named/etc/rndc.key \
				    >/dev/null 2>&1
				echo done.
			else
				echo failed.
			fi
		fi
	fi

	if [ ! -f /etc/isakmpd/private/local.key ]; then
		echo -n "openssl: generating isakmpd/iked RSA key... "
		if openssl genrsa -out /etc/isakmpd/private/local.key 2048 \
		    >/dev/null 2>&1; then
			chmod 600 /etc/isakmpd/private/local.key
			openssl rsa -out /etc/isakmpd/local.pub -in \
			    /etc/isakmpd/private/local.key -pubout \
			    >/dev/null 2>&1
			echo done.
		else
			echo failed.
		fi
	fi

	if [ ! -f /etc/iked/private/local.key ]; then
		# Just copy the generated isakmpd key
		cp /etc/isakmpd/private/local.key /etc/iked/private/local.key
		chmod 600 /etc/iked/private/local.key
		cp /etc/isakmpd/local.pub /etc/iked/local.pub
	fi

	ssh-keygen -A
}

# create Unix sockets directories for X if needed and make sure they have
# correct permissions
setup_X_sockets()
{
	if [ -d /usr/X11R6/lib ]; then
		for d in /tmp/.X11-unix /tmp/.ICE-unix ; do
			if [ -d $d ]; then
				if [ `ls -ld $d | cut -d' ' -f4` \
				    != root ]; then
					chown root $d
				fi
				if [ `ls -ld $d | cut -d' ' -f1` \
				    != drwxrwxrwt ]; then
					chmod 1777 $d
				fi
			elif [ -e $d ]; then
				echo "Error: $d exists and isn't a directory."
			else
				mkdir -m 1777 $d
			fi
		done
	fi
}

do_fsck()
{
	local _flags=$1

	fsck -p $_flags
	case $? in
	0)
		;;
	2)
		exit 1
		;;
	4)
		echo "Rebooting..."
		reboot
		echo "Reboot failed; help!"
		exit 1
		;;
	8)
		echo "Automatic file system check failed; help!"
		exit 1
		;;
	12)
		echo "Boot interrupted."
		exit 1
		;;
	130)
		# interrupt before catcher installed
		exit 1
		;;
	*)
		echo "Unknown error; help!"
		exit 1
		;;
	esac
}

# End subroutines

stty status '^T'

# Set shell to ignore SIGINT (2), but not children;
# shell catches SIGQUIT (3) and returns to single user after fsck.
trap : 2
trap : 3	# shouldn't be needed

HOME=/; export HOME
INRC=1; export INRC
PATH=/sbin:/bin:/usr/sbin:/usr/bin
export PATH

# must set the domainname before rc.conf, so YP startup choices can be made
if [ -f /etc/defaultdomain ]; then
	domainname `stripcom /etc/defaultdomain`
fi

# need to get local functions from rc.subr
FUNCS_ONLY=1 . /etc/rc.d/rc.subr

# load rc.conf into scope
_rc_parse_conf

if [ X"$1" = X"shutdown" ]; then
	if echo 2>/dev/null >>/var/db/host.random || \
	    echo 2>/dev/null >>/etc/random.seed; then
		random_seed
	else
		echo warning: cannot write random seed to disk
	fi

	# If we are in secure level 0, assume single user mode.
	if [ `sysctl -n kern.securelevel` -ne 0 ]; then
		pkg_scripts=${pkg_scripts%%*( )}
		if [ -n "${pkg_scripts}" ]; then
			echo -n 'stopping package daemons:'
			while [ -n "${pkg_scripts}" ]; do
				_r=${pkg_scripts##* }
				pkg_scripts=${pkg_scripts%%*( )${_r}}
				[ -x /etc/rc.d/${_r} ] && /etc/rc.d/${_r} stop
			done
			echo '.'
		fi

		[ -f /etc/rc.shutdown ] && sh /etc/rc.shutdown
	else
		echo single user: not running shutdown scripts
	fi

	# bring carp interfaces down gracefully
	ifconfig | while read a b; do
		case $a in
		carp+([0-9]):) ifconfig ${a%:} down ;;
		esac
	done

	exit 0
fi

swapctl -A -t blk

if [ -e /fastboot ]; then
	echo "Fast boot: skipping disk checks."
elif [ X"$1" = X"autoboot" ]; then
	echo "Automatic boot in progress: starting file system checks."
	do_fsck
fi

trap "echo 'Boot interrupted.'; exit 1" 3

umount -a >/dev/null 2>&1
mount -a -t nonfs,vnd
mount -uw /		# root on nfs requires this, others aren't hurt
rm -f /fastboot		# XXX (root now writeable)

# set flags on ttys.  (do early, in case they use tty for SLIP in netstart)
echo 'setting tty flags'
ttyflags -a

if [ -f /sbin/kbd -a -f /etc/kbdtype ]; then
	kbd `cat /etc/kbdtype`
fi

wsconsctl_conf

if [ X"${pf}" != X"NO" ]; then
	RULES="block all"
	RULES="$RULES\npass on lo0"
	RULES="$RULES\npass in proto tcp from any to any port 22 keep state"
	RULES="$RULES\npass out proto { tcp, udp } from any to any port 53 keep state"
	RULES="$RULES\npass out inet proto icmp all icmp-type echoreq keep state"
	RULES="$RULES\npass out inet proto udp from any port bootpc to any port bootps"
	RULES="$RULES\npass in inet proto udp from any port bootps to any port bootpc"
	if ifconfig lo0 inet6 >/dev/null 2>&1; then
		RULES="$RULES\npass out inet6 proto icmp6 all icmp6-type neighbrsol"
		RULES="$RULES\npass in inet6 proto icmp6 all icmp6-type neighbradv"
		RULES="$RULES\npass out inet6 proto icmp6 all icmp6-type routersol"
		RULES="$RULES\npass in inet6 proto icmp6 all icmp6-type routeradv"
		RULES="$RULES\npass out inet6 proto udp from any port dhcpv6-client to any port dhcpv6-server"
		RULES="$RULES\npass in inet6 proto udp from any port dhcpv6-server to any port dhcpv6-client"
	fi
	RULES="$RULES\npass in proto carp keep state (no-sync)"
	RULES="$RULES\npass out proto carp !received-on any keep state (no-sync)"
	case `sysctl vfs.mounts.nfs 2>/dev/null` in
	*[1-9]*)
		# don't kill NFS
		RULES="set reassemble yes no-df\n$RULES"
		RULES="$RULES\npass in proto { tcp, udp } from any port { 111, 2049 } to any"
		RULES="$RULES\npass out proto { tcp, udp } from any to any port { 111, 2049 } !received-on any"
		;;
	esac
	echo $RULES | pfctl -f -
	pfctl -e
fi

# Fill net.inet.(tcp|udp).baddynamic lists from /etc/services
fill_baddynamic udp
fill_baddynamic tcp

sysctl_conf

# set hostname, turn on network
echo 'starting network'
ifconfig -g carp carpdemote 128
if [ -f /etc/resolv.conf.save ]; then
	mv -f /etc/resolv.conf.save /etc/resolv.conf
	touch /etc/resolv.conf
fi
. /etc/netstart
dmesg > /dev/random	# any write triggers an RC4 rekey

if [ X"${pf}" != X"NO" ]; then
	if [ -f ${pf_rules} ]; then
		pfctl -f ${pf_rules}
	fi
	# bring up pfsync after the working ruleset has been loaded
	if [ -f /etc/hostname.pfsync0 ]; then
		sh /etc/netstart pfsync0
	fi
fi

mount -s /usr >/dev/null 2>&1
mount -s /var >/dev/null 2>&1

random_seed

# clean up left-over files
rm -f /etc/nologin /var/spool/lock/LCK.* /var/spool/uucp/STST/*
(cd /var/run && { rm -rf -- *; install -c -m 664 -g utmp /dev/null utmp; })
(cd /var/authpf && rm -rf -- *)

# save a copy of the boot messages
dmesg >/var/run/dmesg.boot

make_keys

echo -n 'starting early daemons:'
start_daemon syslogd ldattach pflogd named nsd unbound ntpd
start_daemon iscsid isakmpd iked sasyncd ldapd npppd
echo '.'

if [ X"${ipsec}" != X"NO" ]; then
	if [ -f ${ipsec_rules} ]; then
		ipsecctl -f ${ipsec_rules}
	fi
fi

echo -n 'starting RPC daemons:'
start_daemon portmap ypldap
if [ X"`domainname`" != X"" ]; then
	start_daemon ypserv ypbind yppasswdd
fi
start_daemon mountd nfsd lockd statd amd
echo '.'

mount -a
swapctl -A -t noblk

# check and mount networked filesystems
do_fsck -N
mount -a -N

# /var/crash should be a directory or a symbolic link
# to the crash directory if core dumps are to be saved.
if [ -d /var/crash ]; then
	savecore ${savecore_flags} /var/crash
fi

if [ X"${check_quotas}" = X"YES" ]; then
	echo -n 'checking quotas:'
	quotacheck -a
	echo ' done.'
	quotaon -a
fi

kvm_mkdb			# build kvm(3) databases
dev_mkdb
chmod 666 /dev/tty[pqrstuvwxyzPQRST]*
chown root:wheel /dev/tty[pqrstuvwxyzPQRST]*

# check the password temp/lock file
if [ -f /etc/ptmp ]; then
	logger -s -p auth.err \
	    'password file may be incorrect -- /etc/ptmp exists'
fi

echo clearing /tmp

# prune quickly with one rm, then use find to clean up /tmp/[lq]*
# (not needed with mfs /tmp, but doesn't hurt there...)
(cd /tmp && rm -rf [a-km-pr-zA-Z]*)
(cd /tmp &&
    find . ! -name . ! -name lost+found ! -name quota.user \
	! -name quota.group -execdir rm -rf -- {} \; -type d -prune)

setup_X_sockets

[ -f /etc/rc.securelevel ] && sh /etc/rc.securelevel
# rc.securelevel did not specifically set -1 or 2, so select the default: 1
if [ `sysctl -n kern.securelevel` -eq 0 ]; then
	sysctl kern.securelevel=1
fi

# patch /etc/motd
if [ ! -f /etc/motd ]; then
	install -c -o root -g wheel -m 664 /dev/null /etc/motd
fi
if T=`mktemp /tmp/_motd.XXXXXXXXXX`; then
	sysctl -n kern.version | sed 1q > $T
	echo "" >> $T
	sed '1,/^$/d' < /etc/motd >> $T
	cmp -s $T /etc/motd || cp $T /etc/motd
	rm -f $T
fi

if [ X"${accounting}" = X"YES" ]; then
	if [ ! -f /var/account/acct ]; then
		touch /var/account/acct
	fi
	echo 'turning on accounting';	accton /var/account/acct
fi

if [ -f /sbin/ldconfig ]; then
	echo 'creating runtime link editor directory cache.'
	if [ -d /usr/local/lib ]; then
		shlib_dirs="/usr/local/lib $shlib_dirs"
	fi
	if [ -d /usr/X11R6/lib ]; then
		shlib_dirs="/usr/X11R6/lib $shlib_dirs"
	fi
	ldconfig $shlib_dirs
fi

echo 'preserving editor files.';	/usr/libexec/vi.recover

echo -n 'starting network daemons:'
start_daemon ldomd sshd snmpd ldpd ripd ospfd ospf6d bgpd ifstated
start_daemon relayd dhcpd dhcrelay mrouted dvmrpd

if ifconfig lo0 inet6 >/dev/null 2>&1; then
	fw=`sysctl -n net.inet6.ip6.forwarding`
	if [ X"${fw}" = X"0" ]; then
		start_daemon rtsold
	else
		start_daemon route6d rtadvd
	fi
fi

start_daemon hostapd lpd sendmail smtpd slowcgi nginx httpd ftpd
start_daemon ftpproxy tftpd tftpproxy identd inetd rarpd bootparamd
start_daemon rbootd mopd spamd spamlogd sndiod
echo '.'

# If rc.firstime exists, run it just once, and make sure it is deleted
if [ -f /etc/rc.firsttime ]; then
	mv /etc/rc.firsttime /etc/rc.firsttime.run
	. /etc/rc.firsttime.run 2>&1 | tee /dev/tty |
		mail -Es "`hostname` rc.firsttime output" root >/dev/null
fi
rm -f /etc/rc.firsttime.run

# Run rc.d(8) scripts from packages
if [ -n "${pkg_scripts}" ]; then
	echo -n 'starting package daemons:'
	for _r in $pkg_scripts; do
		if [ -x /etc/rc.d/${_r} ]; then
			start_daemon ${_r}
		else
			echo -n " ${_r}(absent)"
		fi
	done
	echo '.'
fi

[ -f /etc/rc.local ] && sh /etc/rc.local

ifconfig -g carp -carpdemote 128	# disable carp interlock

mixerctl_conf
echo -n 'starting local daemons:'
start_daemon apmd sensorsd hotplugd watchdogd cron wsmoused xdm
echo '.'

date
exit 0
