# Common functions shared by LTSP init scripts

# ltsp_config sources ltsp-common-functions
. /usr/share/ltsp/ltsp_config

warn() {
    msg="$1"
    logger -p user.warning -t ltsp-client  "warning: $msg"
}

start_sound() {
    if boolean_is_true "$SOUND" ; then
        case "$SOUND_DAEMON" in
            pulse|'') # The default when no value is set
                # Explicitly allow pulse user access to sound devices, ignore errors
                if [ -x /usr/bin/setfacl ]; then
                    /usr/bin/setfacl -m u:pulse:rw /dev/snd/* > /dev/null 2>&1
                fi

                # Detect method, 0.9.16+ uses module-udev-detect instead of
                # module-detect and module-stream-restore instead of
                # module-volume-restore
                unset PULSE_DETECT
                unset PULSE_VOLUME_RESTORE
                # Replace "awk" with shell built-in "while read"
                case $(pulseaudio --version |while read a b; do echo $b; done) in
                    0.9.1[6-9]*|0.9.[2-9][0-9]*) 
                        PULSE_DETECT=module-udev-detect 
                        PULSE_VOLUME_RESTORE=module-stream-restore 
                        ;;
                    0.[0-9].*) 
                        PULSE_DETECT=module-detect
                        PULSE_VOLUME_RESTORE=module-volume-restore
                        ;;
                    *) 
                        PULSE_DETECT=module-udev-detect 
                        PULSE_VOLUME_RESTORE=module-stream-restore 
                        ;;
                esac
                /usr/bin/pulseaudio --system \
                --exit-idle-time=-1 \
                --disable-shm \
                --no-cpu-limit \
                --resample-method=trivial \
                --high-priority \
                --log-target=syslog \
                -L $PULSE_DETECT \
                -L "module-esound-protocol-tcp auth-anonymous=1" \
                -L "module-native-protocol-tcp auth-anonymous=1" \
                -L $PULSE_VOLUME_RESTORE \
                -L module-rescue-streams \
                -L "module-native-protocol-unix auth-anonymous=1" \
                -n &
                ;;
            esd) 
                /usr/bin/esd -nobeeps -public -tcp &
                ;;
            nasd)
                /usr/bin/nasd -aa &
                # Line copied from old LTSP:  Should we use it? [pere 2006-03-03]
                #aumix-minimal -v100 -w100 -c90 -m10
                ;;
            [Ff][Aa][Ll][Ss][Ee]|[Nn]|[Nn][Oo])
                # Do not do anything if SOUND_DAEMON is False, N, or No
                true
                ;;
            *)
                warn "Unable to start unsupported sound daemon: '$SOUND_DAEMON'"
                ;;
        esac
    fi
}

configure_sound_volume() {
    if boolean_is_true "$SOUND" ; then
        # Set up sound volume
        ## Set higher volume than default if not specified by lts.conf
    
        [ -z "$VOLUME" ]           && VOLUME=90
        [ -z "$PCM_VOLUME" ]       && PCM_VOLUME=90
        
        LANG=C amixer -c0 scontents | while read line; do
            if [ -n "$(echo $line|grep 'Simple mixer control')" ]; then
                channel=$(echo $line|sed -e 's/^Simple mixer control //')
            else
                if [ -n "$channel" ]; then
                    # Translate the channel name into an environmentally
                    # friendly variable.  In other words, a variable
                    # in all caps, where forward slashes, hyphens, and 
                    # spaces are replaced by underscores, and anything
                    # in parentheses is dropped completely
                    # eg. if the channel is named 'Mic Boost (+20dB)'
                    #     then the variable is simply MIC_BOOST_SWITCH
                    #
                    # Oh, and SWITCH is used for on/off switches - value
                    # should be on or off, and VOLUME is used for volumes
                    # where the value should be a number representing a 
                    # percentage
                    channel_name=$(echo ${channel}|sed -e s/^\'// -e s/\'.*$// -e 's/ -//g' -e 's/ [(].*[)]//' -e 's/\//_/g' -e 's/ /_/g' -e 's/-/_/g' |tr [a-z] [A-Z])
                    if [ -n "$(echo $line|grep volume)" ]; then
                        eval channel_vol="\$${channel_name}_VOLUME"
                        if [ "${channel_name}" = "MIC" ]; then 
                            cap="cap"
                        else
                            unset cap
                        fi
                        if boolean_is_true "${VOLUME_MANUAL}"; then
                            [ -n "${channel_vol}" ] && echo sset "${channel}" ${channel_vol}% unmute $cap 
                        else
                            # Set default MIC volumes to 40 if unspecified
                            # This should resolve feedback issues
                            case "${channel_name}" in
                                *MIC*) [ -z "${channel_vol}" ] && channel_vol=40 ;;
                            esac
                            echo sset "${channel}" ${channel_vol:-$VOLUME}% unmute $cap 
                        fi
                    fi
                    if [ -n "$(echo $line|grep switch)" ]; then
                        eval channel_switch="\$${channel_name}_SWITCH"
                        [ -n "${channel_switch}" ] && echo sset "${channel}" ${channel_switch} 
                    fi
                fi
                unset channel
            fi
        done | amixer -c0 --stdin >/dev/null 2>&1
    fi
}

configure_localdev() {
    if boolean_is_true "$LOCALDEV" ; then
        # Make mountpoint dir
        mkdir -p /var/run/drives
        # Make this sessions secret auth cookie for ltspfs
        if [ ! -f /var/run/ltspfs_token ]; then
            mcookie > /var/run/ltspfs_token
        fi
        if [ -z "$(pgrep ltspfsd)" ]; then
            /usr/bin/ltspfsd
        fi
        # cdrom devices are handled by the cdpingerponger
        if [ -z "$(pgrep -l -f -x "/usr/sbin/cdpinger cdrom$")" ]; then
            /usr/sbin/cdpinger cdrom # default for usb cdroms
        fi

        # and start one for every additional cdrom device
        if [ -L /dev/cdrom?* ];then
            for CDDEV in $(ls /dev/cdrom?*); do
                if [ -z "$(pgrep -l -f -x "/usr/sbin/cdpinger ${CDDEV}$")" ]; then
                    /usr/sbin/cdpinger $(basename ${CDDEV})
                fi
            done
        fi
    fi
}

configure_swap() {
    if boolean_is_true "$USE_LOCAL_SWAP" ; then
        # Enable local swap partition if found on local disk
        for part in `sfdisk -l 2>/dev/null | awk '/ 82 / { print $1}'`; do
            swap_devices="$swap_devices $part"
        done
    fi

    # Enable NBD_SWAP for clients with RAM < NBD_SWAP_THRESHOLD (in MB)
    if [ -n "$NBD_SWAP_THRESHOLD" ] && [ -z "$NBD_SWAP" ] && [ -z "$swap_devices" ]; then
        memtotal=$(sed -n 's/MemTotal: *\([0-9]*\) .*/\1/p' /proc/meminfo)
        # Clients with less than 48 MB RAM already got a network swap in ltsp_nbd
        if [ "$memtotal" -ge 49152 ] && [ "$memtotal" -lt $((1024*$NBD_SWAP_THRESHOLD)) ]; then
            echo "Only found ${memtotal}k main ram, trying network swap."
            NBD_SWAP=true
        fi
    fi

    if boolean_is_true "$NBD_SWAP" ; then
        NBD_SWAP_SERVER=${NBD_SWAP_SERVER:-"$SERVER"}
        NBD_SWAP_PORT=${NBD_SWAP_PORT:-"9572"}
        modprobe nbd
        # Detect first unused nbd device, skip nbd0
        for num in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15; do
            nbd-client -c /dev/nbd${num} > /dev/null
            [ $? -eq 1 ] && break
        done
        nbd-client $NBD_SWAP_SERVER $NBD_SWAP_PORT /dev/nbd${num} -swap && \
            swap_devices="$swap_devices /dev/nbd${num}"
    fi

    if boolean_is_true "$ENCRYPT_SWAP" ; then
        if [ -x /sbin/cryptsetup ]; then
            modprobe dm_crypt
        else
            echo "ERROR: ENCRYPT_SWAP=Y, but /sbin/cryptsetup not found. disabling swap."
            swap_devices=""
        fi
    fi

    num=0
    for device in $swap_devices ; do
        swap="$device"
        if boolean_is_true "$ENCRYPT_SWAP" ; then
            if [ -x /sbin/cryptsetup ]; then
                cryptsetup -d /dev/urandom create swap$num $swap && swap="/dev/mapper/swap$num"
                num=$(($num+1))
            fi
        fi
        mkswap $swap
        swapon $swap
    done

    # If any swap device was used, there's no need for compcache, so unload it to
    # gain that 25% of RAM. It makes a significant difference on low end clients.
    if [ -n "$swap_devices" ]; then
        for swap in /dev/ramzswap*; do
            if [ -b "$swap" ]; then
                swapoff "$swap" && remove_ramzswap=true || true
            fi
        done
        if [ -n "$remove_ramzswap" ]; then
            modprobe -r ramzswap || true
        fi
    fi
}

configure_printer() {
    for I in 0 1 2; do
        eval DEVICE=\$\{PRINTER_${I}_DEVICE\}
        if [ -n "${DEVICE}" ]; then
            eval PORT=\$\{PRINTER_${I}_PORT:="910${I}"\} 
            eval BAUD=\$\{PRINTER_${I}_SPEED:-"9600"\}
            eval SIZE=\$\{PRINTER_${I}_DATABITS:-"8"\}
            eval PARITY=\$\{PRINTER_${I}_PARITY:-"none"\}
            eval FLOW=\$\{PRINTER_${I}_FLOWCTRL:-"soft"\}

            JETPIPE_ARGS=
            [ -n "$BAUD" ] && JETPIPE_ARGS="${JETPIPE_ARGS} -b ${BAUD}"
            [ -n "$SIZE" ] && JETPIPE_ARGS="${JETPIPE_ARGS} -y ${SIZE}"
            [ -n "$PARITY" ] && JETPIPE_ARGS="${JETPIPE_ARGS} -p ${PARITY}"
            if [ -n "$FLOW" ]; then
                if [ "$FLOW" = "soft" ]; then
                    JETPIPE_ARGS="${JETPIPE_ARGS} -x"  
                else
                    JETPIPE_ARGS="${JETPIPE_ARGS} -r" 
                fi
            fi

            /usr/sbin/jetpipe ${JETPIPE_ARGS} ${DEVICE} ${PORT}
        fi
    done
}

configure_scanner() {
    if boolean_is_true "$SCANNER" ; then
        saned -a
    fi
}

configure_serial_mouse() {
      if [ -n "$X_MOUSE_DEVICE" ] && \
          [ -n "$X_MOUSE_PROTOCOL" ] && \
          type inputattach >/dev/null 2>/dev/null ; then
          case "${X_MOUSE_DEVICE}" in 
              *ttyS*) inputattach --"$X_MOUSE_PROTOCOL" "$X_MOUSE_DEVICE" & ;;
          esac
      fi
}

set_time() {
    # Set up timezone
    if [ -n "$TIMEZONE" ] && [ -e "/usr/share/zoneinfo/$TIMEZONE" ]; then
        cp /usr/share/zoneinfo/$TIMEZONE /etc/localtime 2>/dev/null
    fi

    # Set timeserver to $SERVER if set to autodetect
    if [ "$TIMESERVER" = "auto" ]; then
        TIMESERVER=${SERVER}
    fi

    # Set up timeserver
    if [ -n "$TIMESERVER" ]; then
        (ntpdate $TIMESERVER; hwclock --systohc --utc --noadjfile) &
    fi

}

load_modules() {
    for module in $(env|grep ^MODULE_|sed -e s/^MODULE_[0-9]*\=//|sed -e s/\ /*/);do
        modprobe $(echo $module|tr "*" " ")
    done
}

configure_console() {
    if [ -n "$CONSOLE_KEYMAP" ]; then
        ckbcomp -model pc105 "$CONSOLE_KEYMAP" | loadkeys
    fi
}

configure_resolver() {
    hostname=$(cat /proc/sys/kernel/hostname)
    if [ -z "$hostname" ] || [ "$hostname" = "(none)" ]; then
        # ensure a default hostname, otherwise /etc/hosts may get borked.
        hostname=ltsp
        echo $hostname > /proc/sys/kernel/hostname || true
    fi
    cat <<EOF > /etc/hosts
127.0.0.1 localhost
127.0.0.2 $hostname
$SERVER server
EOF
    if [ -f /etc/hosts.ltsp ]; then
        cat /etc/hosts.ltsp >> /etc/hosts
    fi

    if [ -n "$DNS_SERVER" ] || [ -n "$SEARCH_DOMAIN" ]; then
        :>/etc/resolv.conf
        if [ -n "$SEARCH_DOMAIN" ]; then
            echo "search $SEARCH_DOMAIN" >> /etc/resolv.conf
        fi
        if [ -n "$DNS_SERVER" ]; then
            for n in $DNS_SERVER; do 
                echo "nameserver ${n}" >> /etc/resolv.conf
            done
        fi
    fi
}

configure_syslog() {
    if [ -z "$SYSLOG" ] || [ "$SYSLOG" = "remote" ]; then
        syslog_conf=/etc/syslog.conf
        if [ -d /etc/rsyslog.d ]; then
            syslog_conf=/etc/rsyslog.d/ltsp.conf   
            touch $syslog_conf
        fi
        if [ -f "$syslog_conf" ]; then
            cat <<EOF > "$syslog_conf"
*.* @${SYSLOG_HOST:-$SERVER}
EOF
        fi
    fi
}

configure_fstab() {
    if [ -z "$CONFIGURE_FSTAB" ] || boolean_is_true "$CONFIGURE_FSTAB" ; then
        echo "/dev/root     /       rootfs defaults        0       0" > /etc/fstab
        echo "tmpfs         /tmp    tmpfs   defaults,nosuid,nodev 0 0" >> /etc/fstab
        mount /tmp
    fi
}

configure_home() {
    test -n "$NFS_HOME" || return 0

    # if $NFS_HOME doesn't contain a <server-ip>:/ part
    if [ "$NFS_HOME" = ${NFS_HOME#*:/} ]; then
        NFS_HOME="$SERVER:/$NFS_HOME"
    fi
    NFS_HOME_OPTIONS=${NFS_HOME_OPTIONS:-defaults}
    if ! mount -t nfs -o "$NFS_HOME_OPTIONS" "$NFS_HOME" /home; then
        unset NFS_HOME
    else
        if [ -z "$CONFIGURE_FSTAB" ] || boolean_is_true "$CONFIGURE_FSTAB" ; then
            echo "$NFS_HOME /home   nfs    $NFS_HOME_OPTIONS        0       0" >> /etc/fstab
        fi
    fi
}

configure_cron() {
    CRON_FILE=/etc/cron.d/ltsp
    if [ ! -w "/etc/cron.d" ]; then
        echo "Warning: /etc/cron.d is not writeable."
        return 1
    fi
    if [ -n "$SHUTDOWN_TIME" ] ; then
        echo $SHUTDOWN_TIME | awk -F : '{print $2" "$1" * * * root test ! -S \"$(ls -1 /var/run/ldm_socket_* | head -1)\" && PATH=\$PATH:/sbin/ poweroff -fp" }' >> $CRON_FILE
    fi
    for ltsconf in /etc/lts.conf /var/cache/getltscfg-cluster/lts.conf; do
        if [ -f $ltsconf ]; then
            cat $ltsconf | grep -E "^[[:blank:]]*CRONTAB_[0-9]{2}[[:blank:]]*=" | sed -e "s/[[:blank:]]*CRONTAB_[0-9]\{2\}[[:blank:]]*=[[:blank:]]*\"//g" -e "s/\"[[:blank:]]*$//g" >> $CRON_FILE
        fi
    done
}

run_rcfiles() {
    for i in 01 02 03 04 05 06 07 08 09 10; do
        eval rcfile=\${RCFILE_${i}}
        [ -x "$rcfile" ] && "$rcfile" $@
    done
}

bind_mounts () {
    # set defaults
    test -z "$tmpfs_dir" && tmpfs_dir=/var/lib/ltsp-client-setup
    mount -t tmpfs -o mode=0755 tmpfs $tmpfs_dir
    bind_missing=""
    # preserve directory structure
    for d in $rw_dirs ; do
        if [ -d "$d" ]; then
            cd $tmpfs_dir
            tar --no-recursion -cpf - $(find $d -type d 2> /dev/null) 2> /dev/null | tar xpf -
            mount --bind $tmpfs_dir/$d $d
        else
            bind_missing="$bind_missing $d"
        fi
    done
    # copy contents into tmpfs
    for d in $copy_dirs $temp_copy_dirs; do
        if [ -d "$d" ]; then
            cd $tmpfs_dir
            tar -cpf - $d 2> /dev/null | tar xpf -
            mount --bind $tmpfs_dir/$d $d
        else
            bind_missing="$bind_missing $d"
        fi
    done
    # mount one file on top of another
    for f in $bindfiles ; do
        if [ -e "$f" ]; then
            mkdir -p "$(dirname $tmpfs_dir/$f)"
            cp $f $tmpfs_dir/$f
            mount --bind $tmpfs_dir/$f $f
        else
            bind_missing="$bind_missing $f"
        fi
    done
    if [ -n "$bind_missing" ]; then
        echo "note: ltsp: missing files or directories for bind mounting: $bind_missing"
    fi
}

bind_unmounts() {
    for dir in $temp_copy_dirs; do
        umount $dir
        rm -rf $tmpfs_dir/${dir#/}
    done
}

nbd_sendsigs_protection() {
    if [ -n "$NBD_SERVER" ]; then
        # register pids of nbd-client and nbd-proxy so that sendsigs doesn't kill
        # them on shutdown/reboot.

        # FIXME: only register pids relevent to the root filesystem.
        nbd_pids=$(pgrep '^nbd-client|^nbd-proxy')
        for d in /lib/init/rw/sendsigs.omit.d /var/run/sendsigs.omit.d ; do
            if [ -d "$d" ]; then
                for p in $nbd_pids ; do
                    echo "$p" >> "$d"/ltsp || true
                done
            fi
        done
    fi
}
