diff options
-rw-r--r-- | Makefile | 18 | ||||
-rw-r--r-- | PKGBUILD | 2 | ||||
-rwxr-xr-x | arch-tmpfiles | 250 | ||||
-rw-r--r-- | bash-completion | 22 | ||||
-rw-r--r-- | functions | 341 | ||||
-rw-r--r-- | locale.sh | 3 | ||||
-rwxr-xr-x | netfs | 31 | ||||
-rwxr-xr-x | network | 34 | ||||
-rw-r--r-- | rc.conf | 8 | ||||
-rwxr-xr-x | rc.d | 19 | ||||
-rwxr-xr-x | rc.multi | 14 | ||||
-rwxr-xr-x | rc.shutdown | 151 | ||||
-rwxr-xr-x | rc.single | 56 | ||||
-rwxr-xr-x | rc.sysinit | 305 | ||||
-rw-r--r-- | tmpfiles.conf | 20 | ||||
-rw-r--r-- | zsh-completion | 5 |
16 files changed, 821 insertions, 458 deletions
@@ -1,5 +1,16 @@ VER := $(shell git describe) -DIRS := /etc/rc.d /etc/conf.d /etc/rc.d/functions.d /etc/logrotate.d /sbin /etc/bash_completion.d /usr/share/zsh/site-functions +DIRS := \ + /etc/rc.d \ + /etc/conf.d \ + /etc/rc.d/functions.d \ + /etc/logrotate.d \ + /etc/profile.d \ + /usr/sbin \ + /etc/tmpfiles.d \ + /usr/lib/tmpfiles.d \ + /usr/lib/initscripts \ + /etc/bash_completion.d \ + /usr/share/zsh/site-functions minilogd: minilogd.o @@ -12,7 +23,10 @@ install: minilogd installdirs install -m644 -t $(DESTDIR)/etc/logrotate.d bootlog install -m644 -t $(DESTDIR)/etc/rc.d functions install -m755 -t $(DESTDIR)/etc/rc.d hwclock network netfs - install -m755 -t $(DESTDIR)/sbin minilogd rc.d + install -m755 -t $(DESTDIR)/etc/profile.d locale.sh + install -m755 -t $(DESTDIR)/usr/sbin minilogd rc.d + install -m755 -t $(DESTDIR)/usr/lib/initscripts arch-tmpfiles + install -m644 tmpfiles.conf $(DESTDIR)/usr/lib/tmpfiles.d/arch.conf install -m644 -T bash-completion $(DESTDIR)/etc/bash_completion.d/rc.d install -m644 -T zsh-completion $(DESTDIR)/usr/share/zsh/site-functions/_rc.d @@ -1,6 +1,6 @@ pkgname=initscripts-git pkgver=$(date +%s) -pkgrel=$(git log --pretty=format:%h |head -n 1) +pkgrel=$(git log -1 --pretty=format:%h) pkgdesc="System initialization/bootup scripts" arch=('i686' 'x86_64') url="http://parabolagnulinux.org" diff --git a/arch-tmpfiles b/arch-tmpfiles new file mode 100755 index 0000000..f133a40 --- /dev/null +++ b/arch-tmpfiles @@ -0,0 +1,250 @@ +#!/bin/bash +# +# /usr/lib/initscripts/arch-tmpfiles +# +# Control creation, deletion, and cleaning of volatile and temporary files +# + +warninvalid() { + printf "arch-tmpfiles: ignoring invalid entry on line %d of \`%s'\n" "$LINENUM" "$FILE" + (( ++error )) +} >&2 + +checkparams() { + local parmreq=$1; shift + local path=$1 mode=$2 uid=$3 gid=$4 + + # parmcount must be >= parmreq + if (( $# < parmreq )); then + return 1 + fi + + # mode must be valid octal and 3 or 4 digits + if [[ $mode && ! $mode =~ ^[0-7]{3,4}$ ]]; then + return 1 + fi + + # uid must be numeric or a valid user name + if [[ $uid && $uid != +([[:digit:]]) ]] && ! getent passwd "$uid" >/dev/null; then + return 1 + fi + + # gid must be numeric or a valid group name + if [[ $gid && $gid != +([[:digit:]]) ]] && ! getent group "$gid" >/dev/null; then + return 1 + fi + + return 0 +} + +_f() { + # Create a file if it doesn't exist yet + local path=$1 mode=$2 uid=$3 gid=$4 + + (( CREATE )) || return 0 + + if ! checkparams 4 "$@"; then + warninvalid + return + fi + + if [[ ! -e $path ]]; then + install -m"$mode" -o"$uid" -g"$gid" /dev/null "$path" + fi +} + +_F() { + # Create or truncate a file + local path=$1 mode=$2 uid=$3 gid=$4 + + (( CREATE )) || return 0 + + if ! checkparams 4 "$@"; then + warninvalid + return + fi + + install -m"$mode" -o"$uid" -g"$gid" /dev/null "$path" +} + +_d() { + # Create a directory if it doesn't exist yet + local path=$1 mode=$2 uid=$3 gid=$4 + + (( CREATE )) || return 0 + + if ! checkparams 4 "$@"; then + warninvalid + return + fi + + if [[ ! -d "$path" ]]; then + install -d -m"$mode" -o"$uid" -g"$gid" "$path" + fi +} + +_D() { + # Create or empty a directory + local path=$1 mode=$2 uid=$3 gid=$4 + + (( CREATE )) || return 0 + + if ! checkparams 4 "$@"; then + warninvalid + return + fi + + if [[ -d $path ]]; then + find "$path" -mindepth 1 -maxdepth 1 -xdev -print0 | xargs -r0 rm -rf + fi + install -d -m"$mode" -o"$uid" -g"$gid" "$path" +} + +_p() { + # Create a named pipe (FIFO) if it doesn't exist yet + local path=$1 mode=$2 uid=$3 gid=$4 + + (( CREATE )) || return 0 + + if ! checkparams 4 "$@"; then + warninvalid + return + fi + + if [[ ! -p "$path" ]]; then + mkfifo -m$mode "$path" + chown "$uid:$gid" "$path" + fi +} + +_x() { + # Ignore a path during cleaning. Use this type to exclude paths from clean-up as + # controlled with the Age parameter. Note that lines of this type do not + # influence the effect of r or R lines. Lines of this type accept shell-style + # globs in place of of normal path names. + : + # XXX: we don't implement this +} + +_r() { + # Remove a file or directory if it exists. This may not be used to remove + # non-empty directories, use R for that. Lines of this type accept shell-style + # globs in place of normal path names. + local path + local -a paths=($1) + + (( REMOVE )) || return 0 + + if ! checkparams 1 "$@"; then + warninvalid + return + fi + + for path in "${paths[@]}"; do + if [[ -f $path ]]; then + rm -f "$path" + elif [[ -d $path ]]; then + rmdir "$path" + fi + done +} + +_R() { + # Recursively remove a path and all its subdirectories (if it is a directory). + # Lines of this type accept shell-style globs in place of normal path names. + local path + local -a paths=($1) + + (( REMOVE )) || return 0 + + if ! checkparams 1 "$@"; then + warninvalid + return + fi + + for path in "${paths[@]}"; do + [[ -d $path ]] && rm -rf --one-file-system "$path" + done +} + +shopt -s nullglob + +declare -i CREATE=0 REMOVE=0 CLEAN=0 error=0 LINENO=0 +declare FILE= +declare -A fragments +declare -a tmpfiles_d=( + /usr/lib/tmpfiles.d/*.conf + /etc/tmpfiles.d/*.conf + /run/tmpfiles.d/*.conf +) + +while (( $# )); do + case $1 in + --create) CREATE=1 ;; + --remove) REMOVE=1 ;; + esac + shift +done + +if (( !(CREATE + REMOVE) )); then + printf 'usage: %s [--create] [--remove]\n' "${0##*/}" + exit 1 +fi + +# directories declared later in the tmpfiles_d array will override earlier +# directories, on a per file basis. +# Example: `/etc/tmpfiles.d/foo.conf' supersedes `/usr/lib/tmpfiles.d/foo.conf'. +for path in "${tmpfiles_d[@]}"; do + [[ -f $path ]] && fragments[${path##*/}]=${path%/*} +done + +# catch errors in functions so we can exit with something meaningful +set -E +trap '(( ++error ))' ERR + +# loop through the gathered fragments, sorted globally by filename. +# `/run/tmpfiles/foo.conf' will always be read after `/etc/tmpfiles.d/bar.conf' +while read -d '' fragment; do + LINENUM=0 + + printf -v FILE '%s/%s' "${fragments[$fragment]}" "$fragment" + + ### FILE FORMAT ### + # XXX: We ignore the final 'Age' parameter + # 0 1 2 3 4 5 + # Type Path Mode UID GID Age + # d /run/user 0755 root root 10d + + # omit read's -r flag to honor escapes here, so that whitespace can be + # escaped for paths. We will _not_ honor quoted paths. + while read -a line; do + (( ++LINENUM )) + + # skip over comments and empty lines + if (( ! ${#line[*]} )) || [[ ${line[0]:0:1} = '#' ]]; then + continue + fi + + # whine about invalid entries + if ! type -t _${line[0]} >/dev/null; then + warninvalid + continue + fi + + # fall back on defaults when parameters are passed as '-' + if [[ ${line[2]} = '-' ]]; then + case ${line[0]} in + p|f|F) line[2]=0644 ;; + d|D) line[2]=0755 ;; + esac + fi + [[ ${line[3]} = '-' ]] && line[3]=0 + [[ ${line[4]} = '-' ]] && line[4]=0 + + _${line[0]} "${line[@]:1}" + done <"$FILE" +done < <(printf '%s\0' "${!fragments[@]}" | sort -z) + +exit $error + +# vim: set ts=2 sw=2 noet: diff --git a/bash-completion b/bash-completion index 5151972..d78484e 100644 --- a/bash-completion +++ b/bash-completion @@ -1,22 +1,24 @@ # rc.d bash completion by Seblu <seblu@seblu.net> -_rc.d () +_rc_d() { - local action="help list start stop reload restart" - local cur="${COMP_WORDS[COMP_CWORD]}" - local caction="${COMP_WORDS[1]}" - if ((${COMP_CWORD} == 1)); then + local action cur prev + action="help list start stop reload restart" + _get_comp_words_by_ref cur prev + if ((COMP_CWORD == 1)); then COMPREPLY=($(compgen -W "${action}" -- "$cur")) - elif [[ "$caction" =~ help|list ]]; then + elif [[ "$prev" == help ]]; then COMPREPLY=() - elif [[ "$caction" == start ]]; then + elif [[ "$prev" == list ]]; then + ((COMP_CWORD == 2)) && COMPREPLY=($(compgen -W "started stopped" -- "$cur")) || COMPREPLY=() + elif [[ "$prev" == start ]]; then COMPREPLY=($(comm -23 <(cd /etc/rc.d && compgen -f -X 'functions*' "$cur"|sort) <(cd /run/daemons/ && compgen -f "$cur"|sort))) - elif [[ "$caction" =~ stop|restart|reload ]]; then + elif [[ "$prev" =~ stop|restart|reload ]]; then COMPREPLY=($(cd /run/daemons/ && compgen -f "$cur"|sort)) - elif ((${COMP_CWORD} > 1)); then + elif ((COMP_CWORD > 1)); then COMPREPLY=($(cd /etc/rc.d && compgen -f -X 'functions*' "$cur"|sort)) fi } -complete -F _rc.d rc.d +complete -F _rc_d rc.d # vim: set ts=2 sw=2 ft=sh noet: @@ -2,32 +2,56 @@ # initscripts functions # -# width: +# sanitize PATH (will be overridden later when /etc/profile is sourced, but is useful for UDev) +export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" -STAT_COL=80 -if [[ ! -t 1 ]]; then - USECOLOR="" -elif [[ -t 0 ]]; then - # stty will fail when stdin isn't a terminal - STAT_COL="$(/bin/stty size)" - # stty gives "rows cols"; strip the rows number, we just want columns - STAT_COL="${STAT_COL##* }" -elif /bin/tput cols &>/dev/null; then - # is /usr/share/terminfo already mounted, and TERM recognized? - STAT_COL=$(/bin/tput cols) +if [[ $1 == "start" ]]; then + if [[ $STARTING ]]; then + echo "A daemon is starting another daemon, this is unlikely to work as intended." + else + export STARTING=1 + fi fi -if ((STAT_COL==0)); then - # if output was 0 (serial console), set default width to 80 + +# width: +calc_columns () { STAT_COL=80 - USECOLOR="" -fi + if [[ ! -t 1 ]]; then + USECOLOR="" + elif [[ -t 0 ]]; then + # stty will fail when stdin isn't a terminal + STAT_COL=$(stty size) + # stty gives "rows cols"; strip the rows number, we just want columns + STAT_COL=${STAT_COL##* } + elif tput cols &>/dev/null; then + # is /usr/share/terminfo already mounted, and TERM recognized? + STAT_COL=$(tput cols) + fi + if (( STAT_COL == 0 )); then + # if output was 0 (serial console), set default width to 80 + STAT_COL=80 + USECOLOR="" + fi -# we use 13 characters for our own stuff -STAT_COL=$(($STAT_COL - 13)) + # we use 13 characters for our own stuff + STAT_COL=$(( STAT_COL - 13 )) + + if [[ -t 1 ]]; then + SAVE_POSITION="\e[s" + RESTORE_POSITION="\e[u" + DEL_TEXT="\e[$(( STAT_COL + 4 ))G" + else + SAVE_POSITION="" + RESTORE_POSITION="" + DEL_TEXT="" + fi +} + +calc_columns # disable colors on broken terminals -TERM_COLORS="$(/bin/tput colors 2>/dev/null)" -if (($? != 3)); then +TERM_COLORS=$(tput colors 2>/dev/null) +if (( $? != 3 )); then case $TERM_COLORS in *[!0-9]*) USECOLOR="";; [0-7]) USECOLOR="";; @@ -43,25 +67,25 @@ unset TZ unset LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY \ LC_MESSAGES LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE \ LC_MEASUREMENT LC_IDENTIFICATION LC_ALL -if [[ $DAEMON_LOCALE =~ yes|YES && -n $LOCALE ]]; then +if [[ $DAEMON_LOCALE = [yY][eE][sS] && $LOCALE ]]; then export LANG="${LOCALE}" else export LANG=C fi # set colors -if [[ $USECOLOR =~ yes|YES ]]; then - if /bin/tput setaf 0 &>/dev/null; then - C_CLEAR="$(tput sgr0)" # clear text - C_MAIN="${C_CLEAR}$(/bin/tput bold)" # main text - C_OTHER="${C_MAIN}$(/bin/tput setaf 5)" # prefix & brackets - C_SEPARATOR="${C_MAIN}$(/bin/tput setaf 0)" # separator - C_BUSY="${C_CLEAR}$(/bin/tput setaf 6)" # busy - C_FAIL="${C_MAIN}$(/bin/tput setaf 1)" # failed - C_DONE="${C_MAIN}" # completed - C_BKGD="${C_MAIN}$(/bin/tput setaf 5)" # backgrounded - C_H1="${C_MAIN}" # highlight text 1 - C_H2="${C_MAIN}$(/bin/tput setaf 6)" # highlight text 2 +if [[ $USECOLOR = [yY][eE][sS] ]]; then + if tput setaf 0 &>/dev/null; then + C_CLEAR=$(tput sgr0) # clear text + C_MAIN=${C_CLEAR}$(tput bold) # main text + C_OTHER=${C_MAIN}$(tput setaf 5) # prefix & brackets + C_SEPARATOR=${C_MAIN}$(tput setaf 0) # separator + C_BUSY=${C_CLEAR}$(tput setaf 6) # busy + C_FAIL=${C_MAIN}$(tput setaf 1) # failed + C_DONE=${C_MAIN} # completed + C_BKGD=${C_MAIN}$(tput setaf 5) # backgrounded + C_H1=${C_MAIN} # highlight text 1 + C_H2=${C_MAIN}$(tput setaf 6) # highlight text 2 else C_CLEAR="\e[m" # clear text C_MAIN="\e[;1m" # main text @@ -69,23 +93,13 @@ if [[ $USECOLOR =~ yes|YES ]]; then C_SEPARATOR="\e[1;30m" # separator C_BUSY="\e[;36m" # busy C_FAIL="\e[1;31m" # failed - C_DONE="${C_MAIN}" # completed + C_DONE=${C_MAIN} # completed C_BKGD="\e[1;35m" # backgrounded - C_H1="${C_MAIN}" # highlight text 1 + C_H1=${C_MAIN} # highlight text 1 C_H2="\e[1;36m" # highlight text 2 fi fi -if [[ -t 1 ]]; then - SAVE_POSITION="\e[s" - RESTORE_POSITION="\e[u" - DEL_TEXT="\e[$(($STAT_COL+4))G" -else - SAVE_POSITION="" - RESTORE_POSITION="" - DEL_TEXT="" -fi - # prefixes: PREFIX_REG="::" @@ -142,24 +156,20 @@ stat_die() { status() { stat_busy "$1" shift - if "$@" >/dev/null 2>&1; then - stat_done - return 0 - fi - stat_fail - return 1 + "$@" &>/dev/null + local ret=$? + (( ret == 0 )) && stat_done || stat_fail + return $ret } # usage : in_array( $needle, $haystack ) # return : 0 - found # 1 - not found -# Copied from makepkg in_array() { - [[ $2 ]] || return 1 local needle=$1; shift local item - for item in "$@"; do - [[ ${item#@} = $needle ]] && return 0 + for item; do + [[ $item = "${needle}" ]] && return 0 done return 1 # Not Found } @@ -167,12 +177,12 @@ in_array() { # daemons: add_daemon() { - [[ -d /run/daemons ]] || /bin/mkdir -p /run/daemons - > /run/daemons/"$1" + [[ -d /run/daemons ]] || mkdir -p /run/daemons + >| /run/daemons/"$1" } rm_daemon() { - /bin/rm -f /run/daemons/"$1" + rm -f /run/daemons/"$1" } ck_daemon() { @@ -186,9 +196,9 @@ have_daemon() { # Check if $1 is started at boot ck_autostart() { - local d - for d in "${DAEMONS[@]}"; do - [[ "$1" = ${d#@} ]] && return 1 + local daemon + for daemon in "${DAEMONS[@]}"; do + [[ $1 = "${daemon#@}" ]] && return 1 done return 0 } @@ -197,8 +207,11 @@ start_daemon() { have_daemon "$1" && /etc/rc.d/"$1" start } +# Never use this function, it causes daemons to be stoped in the wrong order. +# The only way to start a daemon at boot is to add it to the DAEMONS array. ck_depends() { - for daemon in "$@"; do + local daemon + for daemon; do ck_daemon "$daemon" && start_daemon "$daemon" done } @@ -224,11 +237,23 @@ status_stopped() { } ck_status() { - if ! ck_daemon "$1"; then - status_started - else - status_stopped + ! ck_daemon "$1" && status_started || status_stopped +} + +# Return PID of $1 +get_pid() { + pidof -o %PPID $1 || return 1 +} + +# Check if PID-file $1 is still the active PID-file for command $2 +ck_pidfile() { + if [[ -f $1 ]]; then + local fpid ppid + read -r fpid <"$1" + ppid=$(get_pid "$2") + [[ $fpid = "${ppid}" ]] && return 0 fi + return 1 } # PIDs to be omitted by killall5 @@ -238,52 +263,84 @@ add_omit_pids() { omit_pids+=( $@ ) } - -kill_everything() { - # $1 = where we are being called from. - # This is used to determine which hooks to run. +# Stop all daemons +# This function should *never* ever perform any other actions beside calling stop_daemon()! +# It might be used by a splash system etc. to get a list of daemons to be stopped. +stop_all_daemons() { # Find daemons NOT in the DAEMONS array. Shut these down first + local daemon for daemon in /run/daemons/*; do [[ -f $daemon ]] || continue daemon=${daemon##*/} - in_array "$daemon" "${DAEMONS[@]}" || stop_daemon "$daemon" + ck_autostart "$daemon" && stop_daemon "$daemon" done # Shutdown daemons in reverse order - for ((i=${#DAEMONS[@]}-1; i>=0; i--)); do - [[ ${DAEMONS[$i]:0:1} = '!' ]] && continue - ck_daemon ${DAEMONS[$i]#@} || stop_daemon ${DAEMONS[$i]#@} + local i daemon + for (( i=${#DAEMONS[@]}-1; i>=0; i-- )); do + [[ ${DAEMONS[i]} = '!'* ]] && continue + daemon=${DAEMONS[i]#@} + ck_daemon "$daemon" || stop_daemon "$daemon" done +} +kill_all() { # Terminate all processes + # and wait until killall5 reports all done or timeout + # Unfortunately killall5 does not support the 0 signal, so just + # use SIGCONT for checking (which should be ignored). stat_busy "Sending SIGTERM To Processes" - run_hook "$1_prekillall" - local pid k5args="" - for pid in ${omit_pids[@]}; do - k5args+=" -o $pid" - done - /sbin/killall5 -15 $k5args &> /dev/null - /bin/sleep 5 + local i + killall5 -15 ${omit_pids[@]/#/-o } &>/dev/null + for (( i=0; i<20 && $?!=2; i++ )); do + sleep .25 # 1/4 second + killall5 -18 ${omit_pids[@]/#/-o } &>/dev/null + done stat_done stat_busy "Sending SIGKILL To Processes" - /sbin/killall5 -9 $k5args &> /dev/null - /bin/sleep 1 + local i + killall5 -9 ${omit_pids[@]/#/-o } &>/dev/null + for (( i=0; i<4 && $?!=2; i++ )); do + sleep .25 # 1/4 second + killall5 -18 ${omit_pids[@]/#/-o } &>/dev/null + done stat_done +} + +# Start/trigger UDev, load MODULES and settle UDev +udevd_modprobe() { + # $1 = where we are being called from. + # This is used to determine which hooks to run. + status "Starting UDev Daemon" udevd --daemon + + run_hook "$1_udevlaunched" + + stat_busy "Triggering UDev uevents" + udevadm trigger --action=add --type=subsystems + udevadm trigger --action=add --type=devices + stat_done + + # Load modules from the MODULES array defined in rc.conf + [[ -f /proc/modules ]] && (( ${#MODULES[*]} )) && + status "Loading Modules" modprobe -ab "${MODULES[@]}" + + status "Waiting for UDev uevents to be processed" \ + udevadm settle --timeout=${UDEV_TIMEOUT:-30} - run_hook "$1_postkillall" + run_hook "$1_udevsettled" + + # in case loading a module changed the display mode + calc_columns } activate_vgs() { - [[ $USELVM =~ yes|YES && -x /sbin/lvm && -d /sys/block ]] || return + [[ $USELVM = [yY][eE][sS] && -x $(type -P lvm) && -d /sys/block ]] || return 0 # Kernel 2.6.x, LVM2 groups - /sbin/modprobe -q dm-mod 2>/dev/null stat_busy "Activating LVM2 groups" - if /sbin/vgchange --sysinit -a y >/dev/null; then - stat_done - else - stat_fail - fi + modprobe -q dm-mod 2>/dev/null + vgchange --sysinit -a y >/dev/null + (( $? == 0 )) && stat_done || stat_fail } # Arch cryptsetup packages traditionally contained the binaries @@ -301,7 +358,7 @@ read_crypttab() { # $1 = function to call with the split out line from the crypttab local line nspo failed=0 while read line; do - [[ $line && ${line:0:1} != '#' ]] || continue + [[ $line && $line != '#'* ]] || continue eval nspo=("${line%#*}") if $1 "${nspo[0]}" "${nspo[1]}" "${nspo[2]}" "${nspo[*]:3}"; then crypto_unlocked=1 @@ -312,6 +369,75 @@ read_crypttab() { return $failed } +# Filesystem functions +# These can be overridden/reused for customizations like shutdown/loop-fsck. +NETFS="nfs,nfs4,smbfs,cifs,codafs,ncpfs,shfs,fuse,fuseblk,glusterfs,davfs,fuse.glusterfs" + +# Check local filesystems +fsck_all() { + fsck -A -T -C"$FSCK_FD" -a -t "no${NETFS//,/,no},noopts=_netdev" $FORCEFSCK + return $? +} + +# Single-user login and/or automatic reboot after fsck (if needed) +fsck_reboot() { + # $1 = exit code returned by fsck + # Ignore conditions 'FS errors corrected' and 'Cancelled by the user' + (( ($1 | 33) == 33 )) && return 0 + if (( $1 & 2 )); then + echo + echo "********************** REBOOT REQUIRED *********************" + echo "* *" + echo "* The system will be rebooted automatically in 15 seconds. *" + echo "* *" + echo "************************************************************" + echo + sleep 15 + else + 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 + sulogin -p + fi + echo "Automatic reboot in progress..." + umount -a + mount -n -o remount,ro / + reboot -f + exit 0 +} + +mount_all() { + mount -a -t "nosysfs,no${NETFS//,/,no}" -O no_netdev +} + +remove_leftover() { + stat_busy "Removing Leftover Files" + # handle this separately until we declare the non-symlinks obsoleted + [[ ! -L /var/lock ]] && rm -rf /var/lock/* + if [[ ! -L /var/run && -d /var/run ]]; then + find /var/run/ \! -type d -delete + ln -s /run/daemons /var/run/daemons + fi + /usr/lib/initscripts/arch-tmpfiles --create --remove && stat_done || stat_fail +} + +bootlogd_stop() { + [[ -f /run/bootlogd.pid ]] || return 0 + touch /var/log/boot + kill $(< /run/bootlogd.pid) + rm -f /run/bootlogd.pid + sed -i -r -e 's/\^\[\[[0-9]?;?[0-9]?[0-9]?;?[0-9]?[0-9]?[ms]//g' \ + -e 's/\^\[(\[1[0-9]1|%)G//g' -e 's/\^\[\[0;1//g' /var/log/boot +} + ############################### # Custom hooks in initscripts # ############################### @@ -338,21 +464,23 @@ read_crypttab() { # sysinit_udevsettled: after uevents have settled in rc.sysinit # single_udevsettled: after uevents have settled in rc.single # sysinit_premount: before local filesystems are mounted, but after root is mounted read-write in rc.sysinit +# sysinit_postmount: after local filesystems are mounted # shutdown_prekillall: before all processes are being killed in rc.shutdown # single_prekillall: before all processes are being killed in rc.single # shutdown_postkillall: after all processes have been killed in rc.shutdown # single_postkillall: after all processes have been killed in rc.single +# shutdown_postumount: after filesystems are unmounted # shutdown_poweroff: directly before powering off in rc.shutdown # # Declare add_hook and run_hook as read-only to prevent overwriting them. # Too bad we cannot do the same thing with hook_funcs -if [[ $RC_FUNCTIONS_HOOK_FUNCS_DEFINED -ne 1 ]]; then +if (( RC_FUNCTIONS_HOOK_FUNCS_DEFINED != 1 )); then declare -A hook_funcs add_hook() { [[ $1 && $2 ]] || return 1 - hook_funcs["$1"]+=" $2" + hook_funcs[$1]+=" $2" } run_hook() { @@ -371,13 +499,14 @@ fi set_consolefont() { [[ $CONSOLEFONT ]] || return 0 stat_busy "Loading Console Font: $CONSOLEFONT" - #CONSOLEMAP in UTF-8 shouldn't be used - [[ $CONSOLEMAP && ${LOCALE,,} =~ utf ]] && CONSOLEMAP="" - for i in /dev/tty[0-9]*; do - /usr/bin/setfont ${CONSOLEMAP:+-m ${CONSOLEMAP}} \ - $CONSOLEFONT -C ${i} >/dev/null 2>&1 - done - if (($? != 0)); then + #CONSOLEMAP in UTF-8 shouldn't be used + [[ $CONSOLEMAP && ${LOCALE,,} =~ utf ]] && CONSOLEMAP="" + local i + for i in /dev/tty[0-9]*; do + setfont ${CONSOLEMAP:+-m "${CONSOLEMAP}"} \ + "$CONSOLEFONT" -C ${i} &>/dev/null + done + if (( $? )); then stat_fail elif [[ $CONSOLEMAP ]]; then cat <<"EOF" >>/etc/profile.d/locale.sh @@ -394,5 +523,15 @@ for f in /etc/rc.d/functions.d/*; do [[ -e $f ]] && . "$f" done +# Exit current shell if user is not root +need_root() { + (( EUID )) && printf 'You need to be root.\n' && exit 1 +} + +# Quit script if it's not running by root +# This can be disabled in scripts sourcing functions by setting NEED_ROOT=0 +# A local call to need_root can be done to ensure part of script need root privilege +(( ${NEED_ROOT:-0} == 1 )) && need_root + # End of file # vim: set ts=2 sw=2 noet: diff --git a/locale.sh b/locale.sh new file mode 100644 index 0000000..611a797 --- /dev/null +++ b/locale.sh @@ -0,0 +1,3 @@ +. /etc/rc.conf + +export LANG=${LOCALE:=en_US} @@ -4,32 +4,24 @@ . /etc/rc.conf . /etc/rc.d/functions -rc=0 - case "$1" in start) stat_busy "Mounting Network Filesystems" - /bin/mount -a -t nfs,nfs4,smbfs,codafs,ncpfs,cifs,shfs,glusterfs,fuse,fuseblk,fuse.glusterfs,davfs + mount -a -t "$NETFS" rc=$? - /bin/mount -a -O _netdev - if ((rc + $? > 0)); then - stat_fail - else - add_daemon netfs - stat_done - fi + mount -a -O _netdev + (( rc || $? )) && stat_die + add_daemon netfs + stat_done ;; stop) stat_busy "Unmounting Network Filesystems" - /bin/umount -a -O _netdev + umount -a -O _netdev rc=$? - /bin/umount -a -t nfs,nfs4,smbfs,codafs,ncpfs,cifs,shfs,glusterfs,fuse,fuseblk,fuse.glusterfs,davfs - if ((rc + $? > 0)); then - stat_fail - else - rm_daemon netfs - stat_done - fi + umount -a -t "$NETFS" + (( rc || $? )) && stat_die + rm_daemon netfs + stat_done ;; restart) $0 stop @@ -37,7 +29,8 @@ case "$1" in $0 start ;; *) - echo "usage: $0 {start|stop|restart}" + echo "usage: $0 {start|stop|restart}" + exit 1 esac # vim: set ts=2 noet: @@ -9,7 +9,8 @@ done # helper function to determine if legacy network support is needed need_legacy() { - if [[ -z $interface ]]; then + # complain when `interface' is unset and `INTERFACES' has profiles enabled + if [[ -z $interface && ${INTERFACES[@]##!*} ]]; then return 0 # need legacy fi @@ -17,33 +18,42 @@ need_legacy() { } deprecated() { - printf "${C_FAIL}Warning:${C_CLEAR} This functionality is deprecated.\n" + printf "${C_FAIL}Warning:${C_CLEAR} Your network settings are deprecated.\n" printf " Please refer to /etc/rc.conf on how to define a single wired\n" printf " connection, or use a utility such as netcfg.\n" } +have_interface() { + if [[ -z $1 ]]; then + printf "\n${C_FAIL}Error:${C_CLEAR} \`interface' is undefined in /etc/rc.conf\n" + return 1 + fi + + if [[ ! -d /sys/class/net/$1 ]]; then + printf "\n${C_FAIL}Error:${C_CLEAR} unknown interface in /etc/rc.conf: \`%s'\n" "$1" + return 1 + fi +} + network_up() { + have_interface "$interface" || return 1 + ip link set dev $interface up || return 1 if [[ $address ]]; then - for var in netmask gateway; do - if [[ -z ${!var} ]]; then - printf "${C_FAIL}Error: static address defined without $var!\n" - return 1 - fi - done - ip addr add $address/$netmask broadcast ${broadcast:-+} dev $interface || return 1 - ip route add default via $gateway || return 1 + ip addr add $address/${netmask:-24} broadcast ${broadcast:-+} dev $interface || return 1 + [[ $gateway ]] && { ip route add default via $gateway || return 1; } else dhcpcd $DHCPCD_ARGS $interface || return 1 fi } network_down() { + have_interface "$interface" || return 1 + if [[ -f /var/run/dhcpcd-$interface.pid ]]; then dhcpcd -k $interface || return 1 else - ip route del default || return 1 ip addr flush dev $interface || return 1 fi @@ -299,7 +309,7 @@ case "$1" in ;; ifup|ifdown|iflist|rtup|rtdown|rtlist) # deprecation check - need_legacy && deprecated + deprecated $1 $2 ;; *) @@ -9,10 +9,12 @@ # LOCALE: available languages can be listed with the 'locale -a' command # DAEMON_LOCALE: If set to 'yes', use $LOCALE as the locale during daemon # startup and during the boot process. If set to 'no', the C locale is used. -# HARDWARECLOCK: set to "UTC" or "localtime", any other value will result +# HARDWARECLOCK: set to "", "UTC" or "localtime", any other value will result # in the hardware clock being left untouched (useful for virtualization) -# Note: Using "localtime" is discouraged. +# Note: Using "localtime" is discouraged, using "" makes hwclock fall back +# to the value in /var/lib/hwclock/adjfile # TIMEZONE: timezones are found in /usr/share/zoneinfo +# Note: if unset, the value in /etc/localtime is used unchanged # KEYMAP: keymaps are found in /usr/share/kbd/keymaps # CONSOLEFONT: found in /usr/share/kbd/consolefonts (only needed for non-US) # CONSOLEMAP: found in /usr/share/kbd/consoletrans @@ -64,7 +66,7 @@ HOSTNAME="myhost" # Wired network setup # - interface: name of device (required) # - address: IP address (leave blank for DHCP) -# - netmask: subnet mask (ignored for DHCP) +# - netmask: subnet mask (ignored for DHCP) (optional, defaults to 255.255.255.0) # - broadcast: broadcast address (ignored for DHCP) (optional) # - gateway: default route (ignored for DHCP) # @@ -1,14 +1,22 @@ #!/bin/bash +NEED_ROOT=0 # this script can be run without be root . /etc/rc.conf . /etc/rc.d/functions usage() { local name=${0##*/} cat >&2 << EOF -usage: $name action daemon ... +usage: $name <action> <daemon> [daemon] ... + $name list [started|stopped] + $name help + +<daemon> is the name of a script in /etc/rc.d +<action> can be a start, stop, restart, reload, status, ... +WARNING: initscripts are free to implement or not the above actions. e.g: $name list + $name list started $name help $name start sshd gpm EOF @@ -23,13 +31,16 @@ case $1 in usage ;; list) + shift cd /etc/rc.d/ for d in *; do have_daemon "$d" || continue # print running / stopped satus if ! ck_daemon "$d"; then + [[ "$1" == stopped ]] && continue printf "${C_OTHER}[${C_DONE}STARTED${C_OTHER}]" else + [[ "$1" == started ]] && continue printf "${C_OTHER}[${C_FAIL}STOPPED${C_OTHER}]" fi # print auto / manual status @@ -40,7 +51,7 @@ case $1 in fi printf " ${C_CLEAR}$d\n" done - ;; + ;; *) # check min args count (( $# < 2 )) && usage @@ -58,10 +69,12 @@ case $1 in if [[ -x "/etc/rc.d/$i" ]]; then env -i "${ENV[@]}" "/etc/rc.d/$i" "$action" else - printf "${C_OTHER}:: ${C_FAIL}Error: ${C_DONE}Daemon script $i does not exist.\n" + printf "${C_OTHER}:: ${C_FAIL}Error: ${C_DONE}Daemon script \`%s' does not exist or is not executable.${C_CLEAR}\n" \ + "$i" fi (( ret += !! $? )) # clamp exit value to 0/1 done + ;; esac exit $ret @@ -9,7 +9,7 @@ run_hook multi_start # Load sysctl variables if sysctl.conf is present -[[ -r /etc/sysctl.conf ]] && /sbin/sysctl -q -p &>/dev/null +[[ -r /etc/sysctl.conf ]] && sysctl -q -p &>/dev/null # Start daemons for daemon in "${DAEMONS[@]}"; do @@ -20,18 +20,10 @@ for daemon in "${DAEMONS[@]}"; do esac done -if [[ -x /etc/rc.local ]]; then - /etc/rc.local -fi +[[ -x /etc/rc.local ]] && /etc/rc.local run_hook multi_end -if [[ -f /run/bootlogd.pid ]]; then - touch /var/log/boot - kill $(< /run/bootlogd.pid) - rm -f /run/bootlogd.pid - sed -i -r -e 's/\^\[\[[0-9]?;?[0-9]?[0-9]?;?[0-9]?[0-9]?[ms]//g' \ - -e 's/\^\[(\[151|%)G//g' /var/log/boot -fi +bootlogd_stop # vim: set ts=2 sw=2 noet: diff --git a/rc.shutdown b/rc.shutdown index a040bbe..db8f50b 100755 --- a/rc.shutdown +++ b/rc.shutdown @@ -6,10 +6,6 @@ . /etc/rc.conf . /etc/rc.d/functions -export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" - -run_hook shutdown_start - # avoid staircase effect stty onlcr @@ -17,29 +13,33 @@ echo " " printhl "Initiating Shutdown..." echo " " +run_hook shutdown_start + [[ -x /etc/rc.local.shutdown ]] && /etc/rc.local.shutdown -kill_everything shutdown +stop_all_daemons + +run_hook shutdown_prekillall + +kill_all + +run_hook shutdown_postkillall stat_busy "Saving Random Seed" -RANDOM_SEED=/var/lib/misc/random-seed -[[ -d ${RANDOM_SEED%/*} ]] || mkdir -p ${RANDOM_SEED%/*} -: > $RANDOM_SEED -chmod 0600 $RANDOM_SEED -POOL_FILE=/proc/sys/kernel/random/poolsize -if [[ -r $POOL_FILE ]]; then - read POOL_SIZE <$POOL_FILE -else - POOL_SIZE=512 -fi -dd if=/dev/urandom of=$RANDOM_SEED count=1 bs=$POOL_SIZE &> /dev/null + RANDOM_SEED=/var/lib/misc/random-seed + install -TDm 0600 /dev/null $RANDOM_SEED + POOL_FILE=/proc/sys/kernel/random/poolsize + if [[ -r $POOL_FILE ]]; then + read POOL_SIZE < $POOL_FILE + else + POOL_SIZE=512 + fi + dd if=/dev/urandom of=$RANDOM_SEED count=1 bs=$POOL_SIZE &>/dev/null stat_done -if [[ $TIMEZONE && -e /usr/share/zoneinfo/$TIMEZONE ]]; then - rm -f /etc/localtime +[[ $TIMEZONE ]] && status "Saving Time Zone" \ - cp "/usr/share/zoneinfo/$TIMEZONE" /etc/localtime -fi + cp --remove-destination "/usr/share/zoneinfo/$TIMEZONE" /etc/localtime # Write to wtmp file before unmounting halt -w @@ -47,58 +47,89 @@ halt -w status "Deactivating Swap" swapoff -a # stop monitoring of lvm2 groups before unmounting filesystems -if [[ $USELVM =~ yes|YES && -x $(type -P lvm) && -d /sys/block ]]; then +[[ $USELVM = [Yy][Ee][Ss] && -x $(type -P lvm) && -d /sys/block ]] && status "Deactivating monitoring of LVM2 groups" \ - vgchange --monitor n >/dev/null 2>&1 -fi + vgchange --monitor n &>/dev/null -stat_busy "Unmounting Filesystems" -if grep -q devtmpfs /proc/filesystems &>/dev/null; then - umount -a -r -t nosysfs,noproc,nodevtmpfs,nodevpts -O no_netdev -else - # if we don't have devtmpfs support, /dev is mounted as tmpfs, so don't unmount it - umount -a -r -t notmpfs,nosysfs,noproc,nodevpts -O no_netdev -fi -stat_done +# if we don't have devtmpfs support, /dev is mounted as tmpfs, so don't unmount it +status "Unmounting Filesystems" \ + umount -a -r -t nodevtmpfs,notmpfs,nosysfs,noproc,nodevpts -O no_netdev + +run_hook shutdown_postumount # Kill non-root encrypted partition mappings -if [[ -f /etc/crypttab && -n $CS ]] && grep -q ^[^#] /etc/crypttab; then +if [[ -f /etc/crypttab && $CS ]] && grep -q ^[^#] /etc/crypttab; then stat_busy "Deactivating encrypted volumes:" - # Maybe someone has LVM on an encrypted block device - # executing an extra vgchange is errorless - if [[ $USELVM =~ yes|YES ]]; then - vgchange --sysinit -a n >/dev/null 2>&1 - fi - do_lock() { - stat_append "${1}.." - if $CS remove "$1" >/dev/null 2>&1; then - stat_append "ok " - else - stat_append "failed " - fi - } - read_crypttab do_lock + # Maybe someone has LVM on an encrypted block device + # executing an extra vgchange is errorless + [[ $USELVM = [Yy][Ee][Ss] ]] && vgchange --sysinit -a n &>/dev/null + do_lock() { + stat_append "${1}.." + if $CS remove "$1" &>/dev/null; then + stat_append "ok " + else + stat_append "failed " + fi + } + read_crypttab do_lock stat_done fi -if [[ $USELVM =~ yes|YES && -x $(type -P lvm) && -d /sys/block ]]; then - status "Deactivating LVM2 groups" vgchange --sysinit -a n >/dev/null 2>&1 -fi +[[ $USELVM = [Yy][Ee][Ss] && -x $(type -P lvm) && -d /sys/block ]] && + status "Deactivating LVM2 groups" vgchange --sysinit -a n &>/dev/null + +if [[ -x /run/initramfs/shutdown ]]; then + + # decide what we want to do + if [[ $RUNLEVEL = 0 ]]; then + action="poweroff" + else + action="reboot" + fi -status "Remounting Root Filesystem Read-only" mount -n -o remount,ro / + # make /run/initrafs a mount + mount --bind /run/initramfs /run/initramfs -run_hook shutdown_poweroff + # in case someone has shared our mountpoints, unshare them + mount --make-private /run/initramfs + mount --make-private / + + # bind all api mounts + mkdir -p /run/initramfs/{sys,proc,dev,run,oldroot} + mount --bind /sys /run/initramfs/sys + mount --bind /proc /run/initramfs/proc + mount --bind /dev /run/initramfs/dev + mount --bind /run /run/initramfs/run + + # enter shutdownramfs + cd /run/initramfs + pivot_root . oldroot + + #reexec init + /oldroot/sbin/init u + + # run /shutdown in the new root + exec chroot . /shutdown $action </dev/console >/dev/console 2>&1 -# Power off or reboot -printsep -if [[ $RUNLEVEL = 0 ]]; then - printhl "${C_H2}POWER OFF" - poweroff -d -f -h -i else - printhl "${C_H2}REBOOTING" - # if kexec is installed and a kernel is loaded, use it - [[ -x $(type -P kexec) ]] && kexec -e > /dev/null 2>&1 - reboot -d -f -i + + status "Remounting Root Filesystem Read-only" \ + mount -n -o remount,ro / + + run_hook shutdown_poweroff + + # Power off or reboot + printsep + if [[ $RUNLEVEL = 0 ]]; then + printhl "${C_H2}POWER OFF" + poweroff -d -f -h -i + else + printhl "${C_H2}REBOOTING" + # if kexec is installed and a kernel is loaded, use it + [[ -x $(type -P kexec) ]] && kexec -e &>/dev/null + reboot -d -f -i + fi + fi # End of file @@ -6,42 +6,32 @@ . /etc/rc.conf . /etc/rc.d/functions -export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" - run_hook single_start if [[ $PREVLEVEL != N ]]; then - kill_everything single - status "Starting UDev Daemon" udevd --daemon - run_hook single_udevlaunched - - # Trigger udev uevents - if pidof -o %PPID /udevd >/dev/null; then - stat_busy "Triggering UDev uevents" - udevadm trigger --action=add --type=subsystems - udevadm trigger --action=add --type=devices - stat_done - fi - - # Wait for udev uevents - if pidof -o %PPID udevd >/dev/null; then - status "Waiting for UDev uevents to be processed" \ - udevadm settle --quiet --timeout=${UDEV_TIMEOUT:-30} - fi - - run_hook single_udevsettled - - # try syslog-NG first, then fall back to good ol' syslogd - if [[ -x /etc/rc.d/syslog-ng ]]; then - /etc/rc.d/syslog-ng start - elif [[ -x /etc/rc.d/syslogd ]]; then - /etc/rc.d/syslogd start - [[ -x /etc/rc.d/klogd ]] && /etc/rc.d/klogd start - fi + + stop_all_daemons + + run_hook single_prekillall + + kill_all + + run_hook single_postkillall + + # start up our mini logger until syslog takes over + minilogd + + # Start/trigger UDev, load MODULES and settle UDev + udevd_modprobe single + + # Removing leftover files + remove_leftover fi run_hook single_end +bootlogd_stop + if [[ $RUNLEVEL = 1 ]]; then printsep printhl "Entering single-user mode..." @@ -50,13 +40,5 @@ if [[ $RUNLEVEL = 1 ]]; then exec init -t1 S fi -if [[ -f /run/bootlogd.pid ]]; then - touch /var/log/boot - kill $(< /run/bootlogd.pid) - rm -f /run/bootlogd.pid - sed -i -r -e 's/\^\[\[[0-9]?;?[0-9]?[0-9]?;?[0-9]?[0-9]?[ms]//g' \ - -e 's/\^\[(\[151|%)G//g' /var/log/boot -fi - # End of file # vim: set ts=2 sw=2 noet: @@ -12,27 +12,17 @@ printhl "${C_H2}http://parabolagnulinux.org" printhl "You're booting into a /libre/ version of Archlinux" printsep -run_hook sysinit_start - -# export standard PATH (will be overridden later when /etc/profile is sourced, but is useful 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) mountpoint -q /proc || mount -n -t proc proc /proc -o nosuid,noexec,nodev mountpoint -q /sys || mount -n -t sysfs sys /sys -o nosuid,noexec,nodev -mountpoint -q /run || mount -n -t tmpfs run /run -o mode=755,size=10M,nosuid,nodev -if ! mountpoint -q /dev; then - if grep -q devtmpfs /proc/filesystems &>/dev/null; then - mount -n -t devtmpfs udev /dev -o mode=0755,size=10M,nosuid - else - mount -n -t tmpfs udev /dev -o mode=0755,size=10M,nosuid - fi -fi -mkdir -p /run/lock /dev/{pts,shm} -chmod 1777 /run/lock -mountpoint -q /dev/pts || mount -n /dev/pts &> /dev/null \ - || mount -n -t devpts devpts /dev/pts -o mode=620,gid=5,nosuid,noexec -mountpoint -q /dev/shm || mount -n /dev/shm &> /dev/null \ +mountpoint -q /run || mount -n -t tmpfs run /run -o mode=0755,size=10M,nosuid,nodev +mountpoint -q /dev || mount -n -t devtmpfs udev /dev -o mode=0755,size=10M,nosuid &>/dev/null \ + || mount -n -t tmpfs udev /dev -o mode=0755,size=10M,nosuid +mkdir -p -m 1777 /run/lock +mkdir -p /dev/{pts,shm} +mountpoint -q /dev/pts || mount -n /dev/pts &>/dev/null \ + || mount -n -t devpts devpts /dev/pts -o mode=0620,gid=5,nosuid,noexec +mountpoint -q /dev/shm || mount -n /dev/shm &>/dev/null \ || 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 @@ -40,10 +30,16 @@ mountpoint -q /dev/shm || mount -n /dev/shm &> /dev/null \ findmnt / --options ro &>/dev/null || status "Mounting Root Read-Only" mount -n -o remount,ro / +run_hook sysinit_start + # start up our mini logger until syslog takes over minilogd bootlogd -p /run/bootlogd.pid +if [[ ! -a /usr/lib ]] ; then + printf "${C_FAIL}/usr is not mounted. This is not supported.${C_OTHER}\n" +fi + HWCLOCK_PARAMS="--systz" case $HARDWARECLOCK in "") ;; @@ -53,86 +49,66 @@ case $HARDWARECLOCK in esac if [[ $HWCLOCK_PARAMS ]]; then - # enable rtc access - 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" - mknod /dev/rtc c $major $minor - done - fi - - # Adjust the system time for timezone offset if rtc is not in UTC - # 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 - hwclock $HWCLOCK_PARAMS - fi + stat_busy "Adjusting system time and setting kernel timezone" + # enable rtc access + 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" + mknod /dev/rtc c $major $minor + done + fi + + # Adjust the system time for timezone offset if rtc is not in UTC + # 1. Make creation time on udev nodes sane (FS#8665) + # 2. Filesystem checks can depend on system time + # 3. This also sets the kernel time zone, used by e.g. vfat + # If TIMEZONE is not set in rc.conf, the timezone stored in /etc/localtime + # is used. If HARDWARECLOCK is not set in rc.conf, the value in + # /var/lib/hwclock/adjfile is used (in this case /var can not be a separate + # partition). + TZ=$TIMEZONE hwclock $HWCLOCK_PARAMS && stat_done || stat_fail fi -status "Starting UDev Daemon" udevd --daemon - -run_hook sysinit_udevlaunched - -stat_busy "Triggering UDev uevents" - udevadm trigger --action=add --type=subsystems - udevadm trigger --action=add --type=devices -stat_done - -# Load modules from the MODULES array defined in rc.conf -mods=${MODULES[@]/!*/} -if [[ $load_modules != off && -f /proc/modules && $mods ]]; then - status "Loading Modules" modprobe --all $mods -fi -unset mods - -status "Waiting for UDev uevents to be processed" \ - udevadm settle --timeout=${UDEV_TIMEOUT:-30} - -run_hook sysinit_udevsettled +# Start/trigger UDev, load MODULES and settle UDev +udevd_modprobe sysinit # bring up the loopback interface [[ -d /sys/class/net/lo ]] && status "Bringing up loopback interface" ip link set up dev lo # FakeRAID devices detection -if [[ $USEDMRAID =~ yes|YES && -x $(type -P dmraid) ]]; then +[[ $USEDMRAID = [Yy][Ee][Ss] && -x $(type -P dmraid) ]] && status "Activating FakeRAID arrays" dmraid -i -ay -fi # BTRFS devices detection -if [[ $USEBTRFS =~ yes|YES && -x $(type -P btrfs) ]]; then +[[ $USEBTRFS = [Yy][Ee][Ss] && -x $(type -P btrfs) ]] && status "Activating BTRFS volumes" btrfs device scan -fi +# Activate LVM2 groups if any activate_vgs # Set up non-root encrypted partition mappings -if [[ -f /etc/crypttab && -n $CS ]] && grep -q ^[^#] /etc/crypttab; then - modprobe -q dm-crypt 2>/dev/null +if [[ -f /etc/crypttab && $CS ]] && grep -q ^[^#] /etc/crypttab; then stat_busy "Unlocking encrypted volumes:" + modprobe -q dm-crypt 2>/dev/null do_unlock() { # $1 = requested name # $2 = source device # $3 = password # $4 = options stat_append "${1}.." - local open=create a="$1" b="$2" failed=0 + 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" + a=$2 + b=$1 fi case $3 in SWAP) @@ -148,11 +124,9 @@ if [[ -f /etc/crypttab && -n $CS ]] && grep -q ^[^#] /etc/crypttab; then # This sanity check _should_ be sufficient, but it might not. # This may cause dataloss if it is not used carefully. blkid -p "$2" &>/dev/null - if [[ $? -eq 2 ]]; then - _overwriteokay=1 - fi + (( $? == 2 )) && _overwriteokay=1 fi - if [[ $_overwriteokay -eq 0 ]]; then + if (( _overwriteokay == 0 )); then false elif $CS -d /dev/urandom $4 $open "$a" "$b" >/dev/null; then stat_append "creating swapspace.." @@ -162,12 +136,12 @@ if [[ -f /etc/crypttab && -n $CS ]] && grep -q ^[^#] /etc/crypttab; then 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 + local ckdev=${3%%:*} + local cka=${3#*:} + local ckb=${cka#*:} + local cka=${cka%:*} + local ckfile=/dev/ckfile + local ckdir=/dev/ckdir case ${cka} in *[!0-9]*) # Use a file on the device @@ -190,7 +164,7 @@ if [[ -f /etc/crypttab && -n $CS ]] && grep -q ^[^#] /etc/crypttab; then *) echo "$3" | $CS $4 $open "$a" "$b" >/dev/null;; esac - if (($? != 0)); then + if (( $? )); then failed=1 stat_append "failed " else @@ -199,137 +173,72 @@ if [[ -f /etc/crypttab && -n $CS ]] && grep -q ^[^#] /etc/crypttab; then 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 + read_crypttab do_unlock && stat_done || stat_fail + # Maybe someone has LVM on an encrypted block device + (( crypto_unlocked == 1 )) && activate_vgs fi -NETFS="nonfs,nonfs4,nosmbfs,nocifs,nocodafs,noncpfs,nosysfs,noshfs,nofuse,nofuseblk,noglusterfs,nodavfs" - +# Check filesystems +[[ -f /forcefsck ]] || in_array forcefsck $(< /proc/cmdline) && FORCEFSCK="-- -f" +declare -r FORCEFSCK +run_hook sysinit_prefsck if [[ -x $(type -P fsck) ]]; then stat_busy "Checking Filesystems" - fsck_reboot() { - echo "Automatic reboot in progress..." - umount -a - mount -n -o remount,ro / - 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 - 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 - 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 - sulogin -p - fsck_reboot - fi - stat_done + fsck_all >|"${FSCK_OUT:-/dev/stdout}" 2>|"${FSCK_ERR:-/dev/stdout}" + declare -r fsckret=$? + (( fsckret <= 1 )) && stat_done || stat_fail +else + declare -r fsckret=0 fi +run_hook sysinit_postfsck + +# Single-user login and/or automatic reboot if needed +fsck_reboot $fsckret -stat_busy "Mounting Local Filesystems" +status "Remounting Root Read/Write" \ 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 $(type -P findmnt) && -e /proc/self/mountinfo ]]; then - findmnt -rnu -o SOURCE,TARGET,FSTYPE,OPTIONS >| /etc/mtab - else - cat /proc/mounts >| /etc/mtab - fi +# don't touch /etc/mtab if it is a symlink to /proc/self/mounts +if [[ ! -L /etc/mtab ]]; then + stat_busy "Creating mtab" + if [[ -x $(type -P findmnt) && -e /proc/self/mountinfo ]]; then + findmnt -rnu -o SOURCE,TARGET,FSTYPE,OPTIONS >| /etc/mtab + else + cat /proc/mounts >| /etc/mtab + fi + (( $? == 0 )) && stat_done || stat_fail +fi - run_hook sysinit_premount - # now mount all the local filesystems - mount -a -t $NETFS -O no_netdev -stat_done +# now mount all the local filesystems +run_hook sysinit_premount +status "Mounting Local Filesystems" \ + mount_all +run_hook sysinit_postmount # enable monitoring of lvm2 groups, now that the filesystems are mounted rw -if [[ $USELVM =~ yes|YES && -x $(type -P lvm) && -d /sys/block ]]; then +[[ $USELVM = [Yy][Ee][Ss] && -x $(type -P lvm) && -d /sys/block ]] && status "Activating monitoring of LVM2 groups" \ vgchange --monitor y >/dev/null -fi status "Activating Swap" swapon -a -if [[ $TIMEZONE && -e /usr/share/zoneinfo/$TIMEZONE ]]; then - rm -f /etc/localtime +[[ $TIMEZONE ]] && status "Configuring Time Zone" \ - cp "/usr/share/zoneinfo/$TIMEZONE" /etc/localtime -fi + cp --remove-destination "/usr/share/zoneinfo/$TIMEZONE" /etc/localtime RANDOM_SEED=/var/lib/misc/random-seed -if [[ -f $RANDOM_SEED ]]; then +[[ -f $RANDOM_SEED ]] && status "Initializing Random Seed" \ - cat $RANDOM_SEED > /dev/urandom -fi + cp $RANDOM_SEED /dev/urandom -stat_busy "Removing Leftover Files" - rm -rf /etc/{nologin,shutdownpid} /forcefsck &>/dev/null - rm -rf /tmp/* /tmp/.* &>/dev/null - [[ ! -L /var/lock ]] && rm -rf /var/lock/* - [[ ! -L /var/run && -d /var/run ]] && find /var/run/ \! -type d -delete - [[ ! -L /var/run && ! -L /var/run/daemons ]] && - rm -rf /var/run/daemons && - ln -s /run/daemons /var/run/daemons - : >| /var/run/utmp - chmod 0664 /var/run/utmp - chown root:utmp /var/run/utmp - # Keep {x,k,g}dm happy with xorg - mkdir -m1777 /tmp/.{X11,ICE}-unix -stat_done +# Remove leftover files +remove_leftover if [[ $HOSTNAME ]]; then stat_busy "Setting Hostname: $HOSTNAME" - echo $HOSTNAME > /proc/sys/kernel/hostname - stat_done + echo "$HOSTNAME" >| /proc/sys/kernel/hostname && stat_done || stat_fail fi -stat_busy "Setting Locale: ${LOCALE:=en_US}" - # Flush old locale settings - : >| /etc/profile.d/locale.sh - 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 @@ -339,9 +248,8 @@ if [[ ${LOCALE,,} =~ utf ]]; then kbd_mode -u < ${i} printf "\e%%G" > ${i} done - echo 1 > /sys/module/vt/parameters/default_utf8 + echo 1 >| /sys/module/vt/parameters/default_utf8 stat_done - [[ $KEYMAP ]] && status "Loading Keyboard Map: $KEYMAP" 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 @@ -349,22 +257,23 @@ else kbd_mode -a < ${i} printf "\e%%@" > ${i} done - echo 0 > /sys/module/vt/parameters/default_utf8 + echo 0 >| /sys/module/vt/parameters/default_utf8 stat_done - [[ $KEYMAP ]] && status "Loading Keyboard Map: $KEYMAP" loadkeys -q $KEYMAP fi +[[ $KEYMAP ]] && + status "Loading Keyboard Map: $KEYMAP" loadkeys -q $KEYMAP # Set console font if required set_consolefont -if [[ -e /proc/sys/kernel/dmesg_restrict && $(< /proc/sys/kernel/dmesg_restrict) -eq 1 ]]; then - : >| /var/log/dmesg.log - chmod 600 /var/log/dmesg.log -else - : >| /var/log/dmesg.log - chmod 644 /var/log/dmesg.log -fi -dmesg >| /var/log/dmesg.log +stat_busy "Saving dmesg Log" + if [[ -e /proc/sys/kernel/dmesg_restrict ]] && + (( $(< /proc/sys/kernel/dmesg_restrict) == 1 )); then + install -Tm 0600 <( dmesg ) /var/log/dmesg.log + else + install -Tm 0644 <( dmesg ) /var/log/dmesg.log + fi +(( $? == 0 )) && stat_done || stat_fail run_hook sysinit_end diff --git a/tmpfiles.conf b/tmpfiles.conf new file mode 100644 index 0000000..7dd1358 --- /dev/null +++ b/tmpfiles.conf @@ -0,0 +1,20 @@ +# +# /usr/lib/tmpfiles.d/arch.conf +# + +D /tmp 1777 root root +D /run/daemons 0755 root root + +d /tmp/.X11-unix 1777 root root +d /tmp/.ICE-unix 1777 root root +d /tmp/.XIM-unix 1777 root root +d /tmp/.font-unix 1777 root root +d /tmp/.Test-unix 1777 root root + +F /var/run/utmp 0664 root utmp + +r /tmp/.X[0-9]-lock +r /etc/nologin +r /etc/shutdownpid +r /forcefsck + diff --git a/zsh-completion b/zsh-completion index f1b7165..e5c2850 100644 --- a/zsh-completion +++ b/zsh-completion @@ -15,9 +15,12 @@ _rc.d () { curcontext="${curcontext%:*:*}:rc.d-${action}:" case $action in - list|help) + help) _arguments "*: :" ;; + list) + _arguments "2: :(started stopped)" + ;; start) _arguments "*: :($(comm -23 <(echo /etc/rc.d/*(N-*:t)|tr ' ' '\n') <(echo /run/daemons/*(N:t)|tr ' ' '\n')))" ;; |