#!/bin/sh
# This file is executed on boot to initialize the system and can also be run by
# the user to start/stop daemons.

# Fallback Configuration Values, to be able to run even with a broken, deleted
# or outdated minirc.conf:
DAEMONS="syslog-ng iptables alsa crond dbus wpa_supplicant dhcpcd sshd privoxy polipo acpid mpd vsftpd lighttpd ntpd haveged"
ENABLED="@syslog-ng @crond @dhcpcd @sshd"
UDEV="busybox"
NETWORK_INTERFACE="eth0"
WIFI_INTERFACE="wlan0"
HOSTNAME="$(cat /etc/hostname)"

# User-definable start/stop/restart/poll functions which fall back to defaults
custom_restart() { default_restart "$@"; }
custom_start()   { default_start   "$@"; }
custom_stop()    { default_stop    "$@"; }
custom_poll()    { default_poll    "$@"; }

. /etc/minirc.conf

on_boot() {
    #===================
    # mount the API filesystem
    # /proc, /sys, /run, /dev, /run/lock, /dev/pts, /dev/shm
    echo_color 3 mounting API filesystem...
    mountpoint -q /proc    || mount -t proc proc /proc -o nosuid,noexec,nodev
    mountpoint -q /sys     || mount -t sysfs sys /sys -o nosuid,noexec,nodev
    mountpoint -q /run     || mount -t tmpfs run /run -o mode=0755,nosuid,nodev
    mountpoint -q /dev     || mount -t devtmpfs dev /dev -o mode=0755,nosuid
    mkdir -p /dev/pts /dev/shm
    mountpoint -q /dev/pts || mount -t devpts devpts /dev/pts -o mode=0620,gid=5,nosuid,noexec
    mountpoint -q /dev/shm || mount -t tmpfs shm /dev/shm -o mode=1777,nosuid,nodev

    #===================
    # initialize system
    echo_color 3 setting up loopback device...
    /usr/sbin/ip link set up dev lo

    echo_color 3 initializing udev...
    if [ "$UDEV" = systemd ]; then
        /usr/lib/systemd/systemd-udevd --daemon
        /usr/bin/udevadm trigger --action=add --type=subsystems
        /usr/bin/udevadm trigger --action=add --type=devices
    elif [ "$UDEV" = eudev ]; then
        /usr/bin/udevd --daemon
        /usr/bin/udevadm trigger --action=add --type=subsystems
        /usr/bin/udevadm trigger --action=add --type=devices
    else # use busybox mdev as fallback:
        busybox mdev -s
        echo /sbin/mdev > /proc/sys/kernel/hotplug
    fi

    echo_color 3 setting hostname...
    echo "$HOSTNAME" >| /proc/sys/kernel/hostname

    echo_color 3 mounting...
    mount -a
    mount -o remount,rw /

    #===================
    # start the default daemons
    echo_color 3 starting daemons...
    for dmn in $ENABLED; do
        if [ "$(echo "$dmn" | awk '{ s=substr($0, 1, 1); print s; }')" = '@' ]; then
            custom_start "$(echo "$dmn" | awk '{ s=substr($0, 2); print s; }')" &
        else
            custom_start "$dmn"
        fi
    done
    
    #===================
    # load /etc/minirc.local
    if [ -x /etc/minirc.local ]; then
        echo_color 3 loading /etc/minirc.local...
        /etc/minirc.local
    fi
}

on_shutdown() {
    #===================
    # stop the default daemons
    echo_color 3 stopping daemons...
    custom_stop all

    #===================
    # load minirc.local.shutdown
    if [ -x /etc/minirc.local.shutdown ]; then
        echo_color 3 loading /etc/minirc.local.shutdown...
        /etc/minirc.local.shutdown
    fi

    #===================
    # shut down udev
    echo_color 3 shutting down udev...
    if [ "$UDEV" = systemd ]; then
        killall systemd-udevd
    elif [ "$UDEV" = eudev ]; then
        killall udevd
    fi

    #===================
    # umount the API filesystem
    echo_color 3 unmounting API filesystem...
    umount -r /run
}

default_start() {
    echo_color 2 starting "$1"...
    case "$1" in
    all)
        for dmn in $DAEMONS $ENABLED; do
            custom_poll "${dmn##@}" || custom_start "${dmn##@}"
        done;;
    alsa)
        alsactl restore;;
    bitlbee)
        su -s /bin/sh -c 'bitlbee -F' bitlbee;;
    dbus)
        mkdir -p /run/dbus &&
            dbus-uuidgen --ensure &&
            dbus-daemon --system;;
    iptables)
        iptables-restore < /etc/iptables/iptables.rules;;
    sshd)
        /usr/bin/sshd;;  # requires an absolute path
    privoxy)
        privoxy --user privoxy.privoxy /etc/privoxy/config;;
    polipo)
        su -c 'polipo daemonise=true logFile="/var/log/polipo.log"' -s /bin/sh - nobody;;
    dhcpcd)
        if ip link | grep -Fq $NETWORK_INTERFACE; then :; else
            echo_color 3 "waiting for $NETWORK_INTERFACE to settle..."
            for i in $(seq 100); do
                ip link | grep -Fq $NETWORK_INTERFACE && break
                sleep 1
            done
        fi
        dhcpcd -nqb;;
    vsftpd)
        vsftpd &;;
    lighttpd)
        lighttpd -f /etc/lighttpd/lighttpd.conf;;
    ntpd)
        ntpd -g -u ntp;;
    wpa_supplicant)
        wpa_supplicant -Dwext -B -i"$WIFI_INTERFACE" -c/etc/wpa_supplicant.conf;;
    icecast)
        icecast -b -c /etc/icecast.xml;;
    *)
        # fallback: start the command
        "$1";;
    esac
}

default_stop() {
    echo_color 1 stopping "$1"...
    case "$1" in
    all)
        for dmn in $DAEMONS $ENABLED; do
            custom_poll "${dmn##@}" && custom_stop "${dmn##@}"
        done;;
    alsa)
        alsactl store;;
    dbus)
        killall dbus-launch
        killall dbus-daemon
        rm /run/dbus/pid;;
    iptables)
        for table in $(cat /proc/net/ip_tables_names); do
            iptables-restore < /var/lib/iptables/empty-"$table".rules
        done;;
    *)
        # fallback: kill all processes with the name of the command
        killall "$1";;
    esac
}

default_restart() {
    case "$1" in
    sshd)
        # Make sure minirc doesn't hang up when restarting it remotely
        busybox setsid sh -c '"$0" stop "$@"; "$0" start "$@"' "$0" "$@";;
    *)
        custom_stop "$@"
        custom_start "$@";;
    esac
}

default_poll() {
    case "$1" in
    alsa)
        return 0;;  # doesn't make much sense for this service
    iptables)
        iptables -L -n | grep -m 1 -q '^ACCEPT\|^REJECT';;
    dbus)
        test -e /run/dbus/pid;;
    *)
        # fallback: check if any processes of that name are running
        pgrep "(^|/)$1\$" >/dev/null 2>&1;;
    esac
}

echo_color() {
  color="$1"
  shift
  printf "\033[1;3%sm%s\033[00m\n" "$color" "$*"
}


#===================
# handle arguments
case "$1" in
init)
    on_boot;;
shutdown)
    on_shutdown;;
start|stop|restart)
    cmd="$1"
    shift
    for dmn in ${@:-$DAEMONS}; do
        custom_"${cmd}" "$dmn"
    done;;
''|list)
    # list all daemons and their status
    for dmn in $DAEMONS; do
        if custom_poll "$dmn" >/dev/null 2>&1; then
            echo_color 2 [X] "$dmn"
        else
            echo_color 0 [ ] "$dmn"
        fi
    done;;
--version)
    echo minirc 0.2;;
*)
    self=$(basename "$0")
    echo "Usage: $self [--help] [--version] <action> [list of daemons]"
    echo
    echo "Actions:"
    echo "   $self list               shows status of all daemons (default action)"
    echo "   $self start [daemons]    starts daemons"
    echo "   $self stop [daemons]     stops daemons"
    echo "   $self restart [daemons]  restarts daemons";;
esac
