### Written for the LFS community by DJ Lucas <dj@linuxfromscratch.org>
##################### THIS SCRIPT ONLY DEMONSTRATES ###########################
###################### what it would do by echoing ############################

### 20071012

#!/bin/bash
# Begin /lib/lsb/install_initd

. /lib/lsb/initd_functions

show_help()
{
    echo "Usage: ${0} [-a /etc/init.d/<scriptname>] [-h]"
    echo "${0} reorganizes the SysV startup symlinks"
    echo "for LSB compliant system initialization scripts."
    echo "Exapmle: ${0} -a /etc/init.d/sample.sh"
    echo ""
    echo "Options:"
    echo "    -a           add an additional script"
    echo ""
    echo "By default, ${0} uses the list of scripts"
    echo "contained in /lib/lsb/scriptlist, which is maintained by"
    echo "/lib/lsb/install_initd and /lib/lsb/remove_initd.  The -a switch"
    echo "is intended for use by /lib/lsb/install_initd when a suitable"
    echo "link value cannot be determined.  Although, not recomended for"
    echo "general use, it is possible for the system administrator to enable"
    echo "an additional script with the -a switch instead of using"
    echo "/lib/lsb/install_initd.  However, none of the usual validity checks"
    echo "are completed on the new script in this case."
    echo ""
}

# Process command line switches
while true
do
    if test ! -n "${1}"
    then
        # There are no more aruments left
        break
    fi

    case "${1}" in

        -h)
            show_help
            exit 0
            ;;

        -a)
            if test -n "${2}"; then
                newscript="${2}"
                shift 2
            else
                echo "Invalid argument!"
                echo ""
                show_help
                exit 1
            fi
            ;;

        -*)
            echo "Invalid argument!"
            echo ""
            show_help
            exit 1
            ;;
    esac
done

# Go ahead and get all the information that is needed from disk in one shot
get_headers

# Give the user something other than dead time
echo -n "Resolving dependencies (this may take a bit)..."

# Cleanup any previous leftovers and create all of our temporary files
rm -rf /tmp/lsbinitd
mkdir /tmp/lsbinitd
touch /tmp/lsbinitd/sysinitstart
for runlevel in 0 1 2 3 4 5 6
do
    touch /tmp/lsbinitd/${runlevel}{start,stop}
done
cp /lib/lsb/scriptlist /tmp/lsbinitd/scriptlist
if test -n "${newscript}"; then
   echo "${newscript}" | sed 's@/etc/init.d/@@' >> /tmp/lsbinitd/scriptlist
fi

# Determine what scripts will be run and in what order 
for runlevel in sysinit 0 1 2 3 4 5 6
do
    # get the scripts that stop in $runlevel
    # skip for sysinit
    if test "${runlevel}" != "sysinit"; then
        for script in `cat /tmp/lsbinitd/scriptlist`
        do
            get_index "${script}"
            get_default_stop 
            echo "${defaultstop}" | grep "${runlevel}" > /dev/null
            if test ${?} -eq 0; then
                stoplist="${stoplist}${script} "
            fi
        done
        unset script
    fi

    # get the scripts that start in $runlevel
    for script in `cat /tmp/lsbinitd/scriptlist`
    do
        get_index "${script}"
        get_default_start
        echo "${defaultstart}" | grep "${runlevel}" > /dev/null
        if test ${?} -eq 0; then
            startlist="${startlist}${script} "
        fi
    done
    unset script

    # Now create some temporary lists so we can handle dependency tracking
    # First, find all scripts for each runlevel that should be stoped
    # Skip sysinit for stop links
    if test "${runlevel}" != "sysinit"; then
        for script in ${stoplist}
        do
            # create entry in the ${runlevel}stop file
            echo -n "${script}:	" >> /tmp/lsbinitd/${runlevel}stop
            get_index ${script} 
            # get previous stop facilities, and convert lsb facility names
            # into script names and send to makefile for dependency tracking
            get_required_stop
            convert_lsb_required "${requiredstop}"
            echo -n "${reqprovideslist}" >> /tmp/lsbinitd/${runlevel}stop
            get_should_stop
            convert_lsb_should "${shouldstop}"
            echo "${optprovideslist}" >> /tmp/lsbinitd/${runlevel}stop
        done
    fi

    # Now, all scripts that should be started by runlevel
    for script in ${startlist}
    do
        # create entry in the ${runlevel}start file
        echo -n "${script}: " >> /tmp/lsbinitd/${runlevel}start
        get_index ${script}
        # get previous start facilities, and convert lsb facility names
        # into script names and send to makefile for dependency tracking
        # in runlevels 0 and 6 we should verify stops, not starts
        if test "${runlevel}" = "0" -o "${runlevel}" = "6"; then
            get_required_stop
            convert_lsb_required "${requiredstop}"
        else
            get_required_start 
            convert_lsb_required "${requiredstart}"
        fi
        echo -n "${reqprovideslist}" >> /tmp/lsbinitd/${runlevel}start
        # Again in runlevels 0 and 6 get stop prereqs
        if test "${runlevel}" = "0" -o "${runlevel}" = "6"; then
            get_should_stop
            convert_lsb_should "${shouldstop}"
        else
            get_should_start
            convert_lsb_should "${shouldstart}"
        fi
        echo "${optprovideslist}" >> /tmp/lsbinitd/${runlevel}start
    done
    unset startlist
    unset stoplist
done

# Now that dependencies are handled completely for each script, fix the    
# startup lists for items who are already started during sysinit and items
# stopped in runlevels 0 and 6.
for runlevel in 1 2 3 4 5
do
    # Get a list of scripts started in sysinit
    for script in `sed -e 's/:.*$//' /tmp/lsbinitd/sysinitstart`
    do
        sed -i "s@ ${script}@@" /tmp/lsbinitd/${runlevel}start
    done
done

# Modify runlevels 0 and 6 start scripts to remove items already stopped
for runlevel in 0 6
do
    # get a list of scripts stopped in $runlevel
    for script in `sed -e 's/:.*$//' /tmp/lsbinitd/${runlevel}stop`
    do
        # and remove them from the deps in the start script
        sed -i "s@ ${script}@@" /tmp/lsbinitd/${runlevel}start
    done
done

# Finish our statement above...
echo "Completed!"

# cycle through the deps and provide an ordered list
## FIXME: There is currently no bail-out logic for reciprocal dependencies
### Update.  A suggested solution is put in place, however, it's based on
###          an educated guess and has no basis on real scripts in the 
###          wild.  See 'FIXME' comment 23 lines below for more details.
echo -n "Generating symlinks..."
for scriptlevel in {0,1,2,3,4,5,6}{start,stop} sysinitstart
do
    unset orderedlist
    count=0
    while test ${count} -lt 12
    do
        unset nodeplist
        nodeplist=`grep -e ":.$" /tmp/lsbinitd/${scriptlevel} | sed 's@:@@g'`
        if test ! -n "${nodeplist}" -a ! -n "$(cat /tmp/lsbinitd/${scriptlevel})"; then
            break
        fi
        for script in `echo "${nodeplist}"`
        do
            orderedlist="${orderedlist} ${script}"
            sed -i -e "s@ ${script}@@g" \
                -e "s@^${script}:@:@g" \
                -e "/^:/d" /tmp/lsbinitd/${scriptlevel}
        done
        count=$(( ${count} + 1 ))
    done
    ## FIXME: This is the fix, however, it is an assumption that may prove
    ##        to be incorrect in practice...I don't know so I left the
    ##        'FIXME' comments in place for now.  If my guess does prove
    ##        to be incorrect, simply increase the loop count.
    # assume that no script will have more than 10 dependencies listed
    if test ${count} -eq 12; then
        echo "Error: Reciprocal dependency detected!"
        echo "Either there is an error in the dependencies of your new script."
        echo "or there are dependency problems with an already installed script."
        echo ""
        echo "The offending scripts and dependencies are listed below:"
        cat /tmp/lsbinitd/${scriptlevel}
        echo ""
        echo "Aborting!"
        exit 1 # generic failure
    fi
    echo "${orderedlist}" > /tmp/lsbinitd/${scriptlevel}
done

# Process starting symlinks
for scriptlevel in {sysinit,0,1,2,3,4,5,6}
do
    count=0
    for script in `cat /tmp/lsbinitd/${scriptlevel}start`
    do
        if test ${count} -lt 10; then
            link="0${count}"
        else
            link="${count}"
        fi

        echo "rm -f /etc/rc${scriptlevel}.d/S??${script}"
        echo "ln -sf ../init.d/${script} /etc/rc${scriptlevel}.d/S${link}${script}"
        count=$(( $count + 5 ))
    done
done

# Process stoping symlinks
for scriptlevel in {0,1,2,3,4,5,6}
do
    count=0
    for script in `cat /tmp/lsbinitd/${scriptlevel}stop`
    do
        if test ${count} -lt 10; then
            link="0${count}"
        else
            link="${count}"
        fi

        echo "rm -f /etc/rc${scriptlevel}.d/K??${script}"
        echo "ln -sf ../init.d/${script} /etc/rc${scriptlevel}.d/K${link}${script}"
        count=$(( $count + 5 ))
    done
done

echo "Completed!"

# Clean up our mess
rm -rf /tmp/lsbinitd

