#!/bin/bash
#
# /etc/rc.sysinit
#

. /etc/rc.conf
. /etc/rc.d/functions

echo " "
printhl "Arch Linux\n"
printhl "${C_H2}http://www.archlinux.org"
printsep

run_hook sysinit_start

# export standard PATH (will be overridden later when /etc/profile is sourced, but is usefull for UDev)
export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"

# mount /proc, /sys, /run, /dev, /run/lock, /dev/pts, /dev/shm (the api filesystems)
/bin/mountpoint -q /proc    || /bin/mount -n -t proc proc /proc -o nosuid,noexec,nodev
/bin/mountpoint -q /sys     || /bin/mount -n -t sysfs sysfs /sys -o nosuid,noexec,nodev
/bin/mountpoint -q /run     || /bin/mount -n -t tmpfs tmpfs /run -o mode=755,size=10M,nosuid,noexec,nodev
if ! /bin/mountpoint -q /dev; then
	if /bin/grep -q devtmpfs /proc/filesystems &>/dev/null; then
		/bin/mount -n -t devtmpfs udev /dev -o mode=0755,size=10M,nosuid
	else
		/bin/mount -n -t tmpfs udev /dev -o mode=0755,size=10M,nosuid
	fi
fi
/bin/mkdir -p /run/lock /dev/{pts,shm}
/bin/chmod 1777 /run/lock
/bin/mountpoint -q /dev/pts || /bin/mount /dev/pts &> /dev/null \
	|| /bin/mount -n -t devpts devpts /dev/pts -o mode=620,gid=5,nosuid,noexec
/bin/mountpoint -q /dev/shm || /bin/mount /dev/shm &> /dev/null \
	|| /bin/mount -n -t tmpfs shm /dev/shm -o mode=1777,nosuid,nodev

# remount root ro to allow for fsck later on, we remount now to
# make sure nothing can open files rw on root which would block a remount
/bin/findmnt / --options ro &>/dev/null || \
status "Mounting Root Read-Only" /bin/mount -n -o remount,ro /

# start up our mini logger until syslog takes over
/sbin/minilogd
/sbin/bootlogd -p /run/bootlogd.pid

# Set console verbosity
for cmdarg in $(< /proc/cmdline); do
        [[ "$cmdarg" == verbose ]] && VERBOSE=8 && break
        [[ "$cmdarg" =~ verbose=[1-8] ]] && VERBOSE=${BASH_REMATCH[0]-8} && break
done
/bin/dmesg -n ${VERBOSE:-3}

HWCLOCK_PARAMS="--hctosys"
case $HARDWARECLOCK in
	UTC) HWCLOCK_PARAMS+=" --utc";;
	localtime) HWCLOCK_PARAMS+=" --localtime";;
	*) HWCLOCK_PARAMS="";;
esac

if [[ $HWCLOCK_PARAMS ]]; then
	# enable rtc access
	/sbin/modprobe -q -a rtc-cmos rtc genrtc
	# If devtmpfs is used, the required RTC device already exists now
	# Otherwise, create whatever device is available
	if ! [[ -c /dev/rtc || -c /dev/rtc0 ]]; then
		for dev in /sys/class/rtc/rtc0/dev /sys/class/misc/rtc/dev; do
			[[ -e $dev ]] || continue
			IFS=: read -r major minor < "$dev"
			/bin/mknod /dev/rtc c $major $minor
		done
	fi

	# Do a clock set here for a few reasons:
	# 1. Make creation time on udev nodes sane (FS#8665)
	# 2. Filesystem checks can depend on system time
	# 3. This will set the clock, if using non-UTC, off the last known
	#    configured timezone. Any new timezone put in rc.conf is copied over at
	#    a later time.
	# This does *NOT* take into account a time adjustment file as /var may not be
	# mounted yet. A second set may occur in rc.d/hwclock to match rc.conf.
	if [[ -f /etc/localtime ]]; then
		/sbin/hwclock $HWCLOCK_PARAMS --noadjfile
	fi
fi

status "Starting UDev Daemon" /sbin/udevd --daemon

run_hook sysinit_udevlaunched

# Trigger udev uevents
if /bin/pidof /sbin/udevd &>/dev/null; then
	stat_busy "Triggering UDev uevents"
	/sbin/udevadm trigger --action=add --type=subsystems
	/sbin/udevadm trigger --action=add --type=devices
	stat_done
fi

# Load modules from the MODULES array defined in rc.conf
mods=${MODULES[@]/!*/}
if [[ $load_modules != off && -f /proc/modules && $mods ]]; then
	status "Loading Modules" /sbin/modprobe --all $mods
fi
unset mods

# Wait for udev uevents
if /bin/pidof /sbin/udevd &>/dev/null; then
	status "Waiting for UDev uevents to be processed" \
		/sbin/udevadm settle --quiet --timeout=${UDEV_TIMEOUT:-30}
fi

run_hook sysinit_udevsettled

# bring up the loopback interface
[[ -d /sys/class/net/lo ]] && \
    status "Bringing up loopback interface" /sbin/ifconfig lo 127.0.0.1 up

# FakeRAID devices detection
if [[ $USEDMRAID =~ yes|YES && -x /sbin/dmraid ]]; then
	status "Activating FakeRAID arrays" /sbin/dmraid -i -ay
fi

# BTRFS devices detection
if [[ $USEBTRFS =~ yes|YES && -x /sbin/btrfs ]]; then
	status "Activating BTRFS volumes" /sbin/btrfs device scan
fi

activate_vgs

# Set up non-root encrypted partition mappings
if [[ -f /etc/crypttab && -n $CS ]] && /bin/grep -q ^[^#] /etc/crypttab; then
	/sbin/modprobe -q dm-crypt 2>/dev/null
	stat_busy "Unlocking encrypted volumes:"
		do_unlock() {
			# $1 = requested name
			# $2 = source device
			# $3 = password
			# $4 = options
			stat_append "${1}.."
			local open=create a="$1" b="$2" failed=0
			# Ordering of options is different if you are using LUKS vs. not.
			# Use ugly swizzling to deal with it.
			# isLuks only gives an exit code but no output to stdout or stderr.
			if $CS isLuks "$2" 2>/dev/null; then
				open=luksOpen
				a="$2"
				b="$1"
			fi
			case $3 in
				SWAP)
					local _overwriteokay=0
					if [[ -b $2 && -r $2 ]]; then
						# This is DANGEROUS! If there is any known file system,
						# partition table, RAID or LVM volume on the device
						# we don't overwrite it.
						#
						# 'blkid' returns 2 if no valid signature has been found.
						# Only in this case we should allow overwriting the device.
						#
						# This sanity check _should_ be sufficient, but it might not.
						# This may cause dataloss if it is not used carefully.
						/sbin/blkid -p "$2" &>/dev/null
						if [[ $? -eq 2 ]]; then
							_overwriteokay=1
						fi
					fi
					if [[ $_overwriteokay -eq 0 ]]; then
						false
					elif $CS -d /dev/urandom $4 $open "$a" "$b" >/dev/null; then
						stat_append "creating swapspace.."
						/sbin/mkswap -f -L $1 /dev/mapper/$1 >/dev/null
					fi;;
				ASK)
					printf "\nOpening '$1' volume:\n"
					$CS $4 $open "$a" "$b" < /dev/console;;
				/dev*)
					ckdev=${3%%:*}
					cka=${3#*:}
					ckb=${cka#*:}
					cka=${cka%:*}
					ckfile=/dev/ckfile
					ckdir=/dev/ckdir
					case ${cka} in
						*[!0-9]*)
							# Use a file on the device
							# cka is not numeric: cka=filesystem, ckb=path
							/bin/mkdir ${ckdir}
							/bin/mount -r -t ${cka} ${ckdev} ${ckdir}
							/bin/dd if=${ckdir}/${ckb} of=${ckfile} >/dev/null 2>&1
							/bin/umount ${ckdir}
							/bin/rmdir ${ckdir};;
						*)
							# Read raw data from the block device
							# cka is numeric: cka=offset, ckb=length
							/bin/dd if=${ckdev} of=${ckfile} bs=1 skip=${cka} count=${ckb} >/dev/null 2>&1;;
					esac
					$CS -d ${ckfile} $4 $open "$a" "$b" >/dev/null
					/bin/dd if=/dev/urandom of=${ckfile} bs=1 count=`stat -c %s ${ckfile}` conv=notrunc >/dev/null 2>&1
					rm ${ckfile};;
				/*)
					$CS -d "$3" $4 $open "$a" "$b" >/dev/null;;
				*)
					echo "$3" | $CS $4 $open "$a" "$b" >/dev/null;;
			esac
			if (($? != 0)); then
				failed=1
				stat_append "failed "
			else
				stat_append "ok "
			fi
			return $failed
		}
	crypto_unlocked=0
	if read_crypttab do_unlock; then
		stat_done
	else
		stat_fail
	fi
	if [[ ${crypto_unlocked} -eq 1 ]]; then
		# Maybe someone has LVM on an encrypted block device
		activate_vgs
	fi
fi

NETFS="nonfs,nonfs4,nosmbfs,nocifs,nocodafs,noncpfs,nosysfs,noshfs,nofuse,nofuseblk,noglusterfs,nodavfs"

if [[ -x /sbin/fsck ]]; then
	stat_busy "Checking Filesystems"
	fsck_reboot() {
		echo "Automatic reboot in progress..."
		/bin/umount -a
		/bin/mount -n -o remount,ro /
		/sbin/reboot -f
		exit 0
	}
	FSCK_OUT=/dev/stdout
	FSCK_ERR=/dev/stdout
	FSCK_FD=
	FORCEFSCK=
	[[ -f /forcefsck ]] && FORCEFSCK="-- -f"
	for cmdarg in $(< /proc/cmdline); do
		[[ "$cmdarg" == forcefsck ]] && FORCEFSCK="-- -f" && break
	done
	run_hook sysinit_prefsck
	/sbin/fsck -A -T -C$FSCK_FD -a -t "$NETFS,noopts=_netdev" $FORCEFSCK >$FSCK_OUT 2>$FSCK_ERR
	fsckret=$?
	if ((fsckret > 1)); then
		stat_fail
	fi
	run_hook sysinit_postfsck
	if (( ( fsckret & 2) == 2)); then
		echo
		echo "********************** REBOOT REQUIRED *********************"
		echo "*                                                          *"
		echo "* The system will be rebooted automatically in 15 seconds. *"
		echo "*                                                          *"
		echo "************************************************************"
		echo
		/bin/sleep 15
		fsck_reboot
	elif ((fsckret > 1 && fsckret != 32)); then
		echo
		echo "*****************  FILESYSTEM CHECK FAILED  ****************"
		echo "*                                                          *"
		echo "*  Please repair manually and reboot. Note that the root   *"
		echo "*  file system is currently mounted read-only. To remount  *"
		echo "*  it read-write type: mount -n -o remount,rw /            *"
		echo "*  When you exit the maintenance shell the system will     *"
		echo "*  reboot automatically.                                   *"
		echo "*                                                          *"
		echo "************************************************************"
		echo
		/sbin/sulogin -p
		fsck_reboot
	fi
	stat_done
fi

status "Mounting Local Filesystems" /bin/mount -n -o remount,rw /

# don't touch /etc/mtab if it is a symlink to /proc/self/mounts
if [[ -L /etc/mtab ]]; then
	:
elif [[ -x /bin/findmnt && -e /proc/self/mountinfo ]]; then
	/bin/findmnt -rnu -o SOURCE,TARGET,FSTYPE,OPTIONS >| /etc/mtab
else
	cat /proc/mounts >| /etc/mtab
fi

run_hook sysinit_premount
# now mount all the local filesystems
/bin/mount -a -t $NETFS -O no_netdev
stat_done

# enable monitoring of lvm2 groups, now that the filesystems are mounted rw
if [[ $USELVM =~ yes|YES && -x /sbin/lvm && -d /sys/block ]]; then
	status "Activating monitoring of LVM2 groups" \
		/sbin/vgchange --monitor y >/dev/null
fi

status "Activating Swap" /sbin/swapon -a

if [[ $TIMEZONE && -e /usr/share/zoneinfo/$TIMEZONE ]]; then
	/bin/rm -f /etc/localtime
	status "Configuring Time Zone" \
		/bin/cp "/usr/share/zoneinfo/$TIMEZONE" /etc/localtime
fi

RANDOM_SEED=/var/lib/misc/random-seed
if [[ -f $RANDOM_SEED ]]; then
	status "Initializing Random Seed" \
		/bin/cat $RANDOM_SEED > /dev/urandom
fi

stat_busy "Removing Leftover Files"
/bin/rm -rf /etc/{nologin,shutdownpid} /forcefsck &>/dev/null
/bin/mountpoint -q /tmp || /bin/rm -rf /tmp/* /tmp/.* &>/dev/null
[[ ! -L /var/lock ]] && /bin/rm -rf /var/lock/*
[[ ! -L /var/run && -d /var/run ]] && /usr/bin/find /var/run/ \! -type d -delete
[[ ! -L /var/run && ! -L /var/run/daemons ]] && /bin/ln -sf /run/daemons /var/run/daemons
: >| /var/run/utmp
/bin/chmod 0664 /var/run/utmp
/bin/chown root:utmp /var/run/utmp
# Keep {x,k,g}dm happy with xorg
/bin/mkdir -m1777 /tmp/.{X11,ICE}-unix
stat_done

#status "Updating Shared Library Links" /sbin/ldconfig

if [[ $HOSTNAME ]]; then
	status "Setting Hostname: $HOSTNAME" /bin/hostname "$HOSTNAME"
fi

# Set the NIS domain name, if necessary
[[ -f /etc/conf.d/nisdomainname ]] && . /etc/conf.d/nisdomainname
if [[ $NISDOMAINNAME ]]; then
	status "Setting NIS Domain Name: $NISDOMAINNAME" \
		/bin/nisdomainname "$NISDOMAINNAME"
fi

stat_busy "Setting Locale: ${LOCALE:=en_US}"
# Flush old locale settings
: >| /etc/profile.d/locale.sh
/bin/chmod 755 /etc/profile.d/locale.sh
# Set user defined locale
echo "export LANG=$LOCALE" >>/etc/profile.d/locale.sh
stat_done

if [[ ${LOCALE,,} =~ utf ]]; then
	stat_busy "Setting Consoles to UTF-8 mode"
	# UTF-8 consoles are default since 2.6.24 kernel
	# this code is needed not only for older kernels,
	# but also when user has set vt.default_utf8=0 but LOCALE is *.UTF-8.
	for i in /dev/tty[0-9]*; do
		/usr/bin/kbd_mode -u < ${i}
		printf "\033%%G" > ${i}
	done
	echo 1 > /sys/module/vt/parameters/default_utf8
	stat_done
	[[ $KEYMAP ]] && status "Loading Keyboard Map: $KEYMAP" /bin/loadkeys -q -u $KEYMAP
else
	stat_busy "Setting Consoles to legacy mode"
	# make non-UTF-8 consoles work on 2.6.24 and newer kernels
	for i in /dev/tty[0-9]*; do
		/usr/bin/kbd_mode -a < ${i}
		printf "\033%%@" > ${i}
	done
	echo 0 > /sys/module/vt/parameters/default_utf8
	stat_done
	[[ $KEYMAP ]] && status "Loading Keyboard Map: $KEYMAP" /bin/loadkeys -q $KEYMAP
fi

# Set console font if required
set_consolefont

# Adding persistent network/cdrom generated rules
# When the rules are generated before /etc is mounted rw they are saved to /run,
# we therefore need to copy this from /run to /etc. This functionality is going away one day.
for f in cd net; do
    [[ -f /run/udev/tmp-rules--70-persistent-$f.rules ]] || continue
    stat_busy "Adding persistent $f udev rules"
    /bin/cat "/run/udev/tmp-rules--70-persistent-$f.rules" >> "/etc/udev/rules.d/70-persistent-$f.rules"
    stat_done
done

/bin/dmesg >| /var/log/dmesg.log

run_hook sysinit_end

# End of file
# vim: set ts=2 sw=2 noet: