On Fri, Jun 29, 2012 at 10:53:03PM +0100, Roger Leigh wrote:
> On Fri, Jun 29, 2012 at 08:27:22PM +0100, Roger Leigh wrote:
> > The following patch implements this behaviour.  While the insserv
> > parsing logic has been tested, it's not been tested for upgrades
> > or whether the whole script works correctly.
> > 
> > - it needs a Depends on insserv (>= $version_with_-s)
> >   ==> this needs your feedback so it can be uploaded.
> > - the preinst could be simplified to just use
> >     update-rc.d "$script" -f defaults
> >   if this is sufficient to update the sequence numbers in the
> >   configuration.  This probably needs running in the postinst TBH.
> > - this just replaces the defaults and user-provided start and stop
> >   arguments with those provided by insserv.  Other than that, there
> >   are no changes to anything else.
> > - You might need to retain support for the old-style logic so that
> >   if other scripts call update-rc.d in the gap between unpacking and
> >   running the postinst, it won't fail.  Just back out the deletions
> >   and run those blocks only if insserv didn't run or didn't find any
> >   matches, which are a trivial addition to the script.
> > 
> > While this patch is just a proof a concept, this should be pretty much
> > all you need.  It just needs checking and testing by someone with
> > file-rc expertise.  If this could be done in the very near future,
> > then that would be great.
> 
> I've attached an updated patch.

Another patch attached.  This one is somewhat more comprehensive.

- insserv support is "optional".  If insserv is not present, it will
  fall back to using static sequence numbers.  This will provide
  backward compatibility for squeeze upgrades.  For new installations
  from wheezy however, it will generate runlevel.conf using insserv.
  For wheezy+1, you'll likely be required to migrate existing users
  to using insserv, but for now it's optional.
- the output functions have been refactored to include start and
  stop entries on separate lines, because this is the common case
  (due to the sequence numbers for start and stop making no sense to
  be the same, unless it's pure coincidence).
- long obsolete code removed from maintainer scripts.

I've documented most of the user-visible change in NEWS.Debian and
the changelog.

The most important change is this: runlevel.conf is no longer user-
editable, except for adding and removing lines.  When using insserv,
the sequence numbers mean nothing, because they are dynamically
generated from the dependency information.  When you run update-rc.d,
the numbers could potentially change if a script is added or removed
from the middle of the sequence, causing all following scripts to be
renumbered.  This means that only two operations are possible:
1. remove a script.  This is equivalent to "update-rc.d remove"
2. add a script.  This is equivalent to
   "update-rc.d defaults|start|stop" (which are all equivalent from
   the insserv POV--they all just add/update the entries for the
   script according to the LSB dependencies)
So if you want to reorder the scripts, you just edit the LSB header
in the init script, and then run "update-rc.d foo defaults" to
effect the change.  This is a change from the historical behaviour
of file-rc, but it's the logical consequence of having dependency-
based boot: you edit the dependencies, not the script numbers.

Hope this all looks reasonable.  I've tested all the insserv
codepaths, but not the non-insserv case yet.  Testing
file-rc -> sysv-rc migration also needs doing (the change to
not restore the rcS links probably needs reverting).  Anyway,
I hope this is useful as a basis for implementing insserv
support in file-rc; hopefully I've done the bulk of the work and
it just remains to test and tweak, or back out any changes you're
unhappy with.  I'd appreciate any feedback; I can make any further
changes you need if you let me know what you want.


Regards,
Roger

-- 
  .''`.  Roger Leigh
 : :' :  Debian GNU/Linux    http://people.debian.org/~rleigh/
 `. `'   schroot and sbuild  http://alioth.debian.org/projects/buildd-tools
   `-    GPG Public Key      F33D 281D 470A B443 6756 147C 07B3 C8BC 4083 E800
diff -urN file-rc-0.8.12/debian/changelog file-rc-0.8.13/debian/changelog
--- file-rc-0.8.12/debian/changelog	2010-04-07 20:30:54.000000000 +0100
+++ file-rc-0.8.13/debian/changelog	2012-07-01 22:20:22.244340652 +0100
@@ -1,3 +1,35 @@
+file-rc (0.8.13) UNRELEASED; urgency=low
+
+  * Use insserv for runlevel defaults rather than the arguments
+    provided to update-rc.d.  The following changes have been made to
+    update-rc.d:
+    - Added new shell functions insserv_find, insserv_find_internal
+      to query insserv for dependency information.  These set the
+      variables previously used for setting the same information from
+      the command-line options, so most of the internal behaviour is
+      unchanged after this point.
+    - For every action which modifies the configuration file, update
+      the settings for each script using the insserv defaults before
+      performing the requested update.  This ensures that the
+      runlevel configuration is always up to date with the current
+      script dependencies.  The effect of this policy is that
+      update-rc.d is really only enabling and disabling services by
+      adding and removing them from runlevel.conf; everything else
+      is effectively delegated to insserv and LSB dependencies.
+    - The code to modify the runlevel.conf has been made into a
+      shell function in order to allow it to be reused.  The first
+      argument is the action to perform (add or remove).
+    - start and stop runlevels for a given script are put onto
+      separate lines, because it's very unlikely the numbers will
+      ever be the same.
+    - Added insserv2file.sh.  This is like rclink2file.sh, but
+      instead of converting the /etc/rc?.d links to
+      /etc/runlevel.conf, it uses the output of insserv -s.
+  * Removed long obsolete logic (prior to oldstable) from maintainer
+    scripts, which is no longer useful for upgrades.
+
+ -- Roger Leigh <rle...@debian.org>  Fri, 29 Jun 2012 19:59:06 +0100
+
 file-rc (0.8.12) unstable; urgency=low
 
   * New maintainer (Closes: #539609)
diff -urN file-rc-0.8.12/debian/NEWS file-rc-0.8.13/debian/NEWS
--- file-rc-0.8.12/debian/NEWS	1970-01-01 01:00:00.000000000 +0100
+++ file-rc-0.8.13/debian/NEWS	2012-06-30 14:08:40.812119041 +0100
@@ -0,0 +1,21 @@
+file-rc (0.8.13) UNRELEASED; urgency=low
+
+  * file-rc now uses LSB dependency information for obtaining the
+    sequence numbers and runlevels when running update-rc.d, rather
+    than using hardcoded static ordering.  This has a number of
+    implications:
+    - The ordering of the scripts is based upon the dependency
+      information, and if a package is installed or removed, this can
+      result in the sequence numbers for the scripts to be recomputed.
+    - This means that the sequence numbers and runlevels in
+      /etc/runlevel.conf will be rewritten and will not preserve
+      manual changes made by the admin.  Editing the numbers in this
+      file no longer makes sense: if these values need to be changed,
+      edit the LSB header in the init script and run
+        update-rc.d scriptname defaults
+      to regenerate the file with the correct numbers.
+    - On upgrade, the existing configuration will be replaced by
+      numbers obtained from the output of insserv -s.  "insserv -s" is
+      used to obtain all script dependency information.
+
+ -- Roger Leigh <rle...@debian.org>  Sat, 30 Jun 2012 14:02:16 +0100
diff -urN file-rc-0.8.12/debian/postinst file-rc-0.8.13/debian/postinst
--- file-rc-0.8.12/debian/postinst	2010-04-07 20:30:54.000000000 +0100
+++ file-rc-0.8.13/debian/postinst	2012-07-01 23:56:58.731720165 +0100
@@ -23,28 +23,17 @@
 #     installation fails and the `postinst' is called with `abort-upgrade',
 #     `abort-remove' or `abort-deconfigure'.
 
+# Make sure insserv is in path
+PATH=/sbin:$PATH
+
 case "$1" in
     configure)
-	# Versions older than 0.4.3 didn't support runlevel S properly.
-	# The easiest way to fix this is to change everything back
-	# to the link structure and then back again to the runlevel file.
-	#
-	if [ "$2" != "" ] && dpkg --compare-versions $2 lt 0.4.3
+	if [ -x /sbin/insserv ] && [ ! -f /etc/runlevel.conf ]
 	then
-	    echo "Updating runlevel.conf to support new runlevel S."
-	    /usr/share/file-rc/rcfile2link.sh \
-		&& rm -f /etc/runlevel.conf /etc/runlevel.fallback
-	    if [ -f /etc/rc0.d/S05halt ] || [ -f /etc/rc6.d/S05reboot ]
-	    then
-		echo "Correcting handling of halt and reboot"
-		[ -f /etc/rc0.d/S05halt ] \
-		    && mv -f /etc/rc0.d/S05halt /etc/rc0.d/S90halt
-		[ -f /etc/rc6.d/S05reboot ] \
-		    && mv -f /etc/rc6.d/S05reboot /etc/rc6.d/S90reboot
-	    fi
-	fi
-
-	if [ -d /etc/rc0.d ] && [ ! -f /etc/runlevel.conf ]
+	    /usr/share/file-rc/insserv2file.sh > /etc/runlevel.conf
+	    cp /etc/runlevel.conf /etc/runlevel.fallback
+	    rm -rf /etc/rc[0-6S].d
+	elif [ -d /etc/rc0.d ] && [ ! -f /etc/runlevel.conf ]
 	then
 	    /usr/share/file-rc/rclink2file.sh > /etc/runlevel.conf
 	    cp /etc/runlevel.conf /etc/runlevel.fallback
diff -urN file-rc-0.8.12/debian/postrm file-rc-0.8.13/debian/postrm
--- file-rc-0.8.12/debian/postrm	2010-04-07 20:30:54.000000000 +0100
+++ file-rc-0.8.13/debian/postrm	2012-07-01 20:24:44.858968220 +0100
@@ -27,7 +27,7 @@
 		ln -sf /usr/share/sysvinit/update-rc.d /usr/sbin/update-rc.d
 	fi
 	if [ ! -e /usr/sbin/invoke-rc.d ] ; then
-		ln -sf /usr/share/sysvinit/update-rc.d /usr/sbin/invoke-rc.d  
+		ln -sf /usr/share/sysvinit/update-rc.d /usr/sbin/invoke-rc.d
 	fi
     ;;
 
diff -urN file-rc-0.8.12/debian/preinst file-rc-0.8.13/debian/preinst
--- file-rc-0.8.12/debian/preinst	2010-04-07 20:30:54.000000000 +0100
+++ file-rc-0.8.13/debian/preinst	2012-07-01 20:24:04.994263373 +0100
@@ -20,50 +20,6 @@
     ;;
 
     upgrade)
-	#
-	# Correct defects in runlevel.{conf|fallback} from file-rc (<< 0.4.1):
-	#
-	for i in runlevel.fallback runlevel.conf; do
-	    sed -e 's/\([0-9][0-9]	-\)[	]\+\(\/etc\/init.d\)/\1	-		\2/g' \
-		/etc/$i > /etc/$i.new
-	    if ! cmp -s /etc/$i /etc/$i.new; then
-		mv /etc/$i.new /etc/$i
-		echo Corrected problem in /etc/$i.
-	    else
-		rm -f /etc/$i.new
-	    fi
-	done
-
-	#
-	# Undo diversions from file-rc (<<0.8.0):
-	#
-	if [ "$2" != "" ] && dpkg --compare-versions $2 lt 0.8.0
-	then
-	    if [ -f /usr/sbin/update-rc.d.links ]
-	    then
-		mv /usr/sbin/update-rc.d.links /usr/sbin/update-rc.d
-	    fi
-	    dpkg-divert --package file-rc --remove \
-		--divert /usr/sbin/update-rc.d.links /usr/sbin/update-rc.d
-	    if [ -f /usr/sbin/invoke-rc.d.links ]
-	    then
-		mv /usr/sbin/invoke-rc.d.links /usr/sbin/invoke-rc.d
-	    fi
-	    dpkg-divert --package file-rc --remove \
-		--divert /usr/sbin/invoke-rc.d.links /usr/sbin/invoke-rc.d
-	    if [ -f /etc/init.d/rc.links ]
-	    then
-		mv -f /etc/init.d/rc.links /etc/init.d/rc
-	    fi
-	    dpkg-divert --package file-rc --remove \
-		--divert /etc/init.d/rc.links /etc/init.d/rc
-	    if [ -f /etc/init.d/rcS.links ]
-	    then
-		mv -f /etc/init.d/rcS.links /etc/init.d/rcS
-	    fi
-	    dpkg-divert --package file-rc --remove \
-		--divert /etc/init.d/rcS.links /etc/init.d/rcS
-	fi
     ;;
 
     abort-upgrade)
diff -urN file-rc-0.8.12/debian/prerm file-rc-0.8.13/debian/prerm
--- file-rc-0.8.12/debian/prerm	2010-04-07 20:30:54.000000000 +0100
+++ file-rc-0.8.13/debian/prerm	2012-07-01 19:31:19.674596135 +0100
@@ -19,7 +19,6 @@
 
 case "$1" in
     remove)
-	/usr/share/file-rc/rcfile2link.sh
         ;;
     upgrade|deconfigure)
 	;;
diff -urN file-rc-0.8.12/debian/rules file-rc-0.8.13/debian/rules
--- file-rc-0.8.12/debian/rules	2010-04-07 20:30:54.000000000 +0100
+++ file-rc-0.8.13/debian/rules	2012-07-01 19:30:49.998081830 +0100
@@ -33,7 +33,7 @@
 	$(installbin) rc rcS $(debroot)/etc/init.d/
 	$(installdoc) rc.README $(debroot)/etc/init.d/README
 	$(installbin) update-rc.d invoke-rc.d $(debroot)/usr/sbin/
-	$(installbin) rclink2file.sh rcfile2link.sh \
+	$(installbin) insserv2file.sh rclink2file.sh rcfile2link.sh \
 		$(debroot)/usr/share/file-rc/
 	$(installdoc) debian/overrides.lintian \
 		$(debroot)/usr/share/lintian/overrides/file-rc
diff -urN file-rc-0.8.12/insserv2file.sh file-rc-0.8.13/insserv2file.sh
--- file-rc-0.8.12/insserv2file.sh	1970-01-01 01:00:00.000000000 +0100
+++ file-rc-0.8.13/insserv2file.sh	2012-07-01 23:45:18.023229684 +0100
@@ -0,0 +1,48 @@
+#! /bin/sh
+
+# insserv2file - Convert insserv dependencies
+# Copyright (C) 1998       Martin Schulze <j...@debian.org>
+# Copyright (C) 1999-2004  Roland Rosenfeld <rol...@debian.org>
+# Copyright (C) 2012       Roger Leigh <rle...@debian.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
+
+# The functions element() and unique() are based on functions
+# written by Winfried Trümper <wi...@xpilot.org>
+
+cat <<EOF
+# This file was automatically generated by $0.
+# You can use update-rc.d(8) to modify it.  Do not edit by hand
+# or else your changes will be lost next time update-rc.d is run.
+# Read runlevel.conf(5) man page for more information about this file.
+#
+# Format:
+# <sort> <off-> <on-levels>     <command>
+EOF
+
+OLDIFS="$IFS"
+IFS=":"
+/sbin/insserv -s | sort  -t: -k2 -k1 | while read IN_ACTION IN_SEQUENCE IN_LEVELS IN_BASENAME
+do
+    IN_LEVELS="$(echo "$IN_LEVELS" | sed -e 's; ;,;g')"
+    if [ "$IN_ACTION" = "S" ]; then
+	echo "$IN_SEQUENCE	-	$IN_LEVELS		/etc/init.d/$IN_BASENAME"
+    elif [ "$IN_ACTION" = "K" ]; then
+	echo "$IN_SEQUENCE	$IN_LEVELS	-		/etc/init.d/$IN_BASENAME"
+    fi
+done
+IFS="$OLDIFS"
+
+echo "# THE LAST LINE IS NEVER READ"
diff -urN file-rc-0.8.12/rclink2file.sh file-rc-0.8.13/rclink2file.sh
--- file-rc-0.8.12/rclink2file.sh	2010-04-07 20:30:54.000000000 +0100
+++ file-rc-0.8.13/rclink2file.sh	2012-07-01 23:45:29.455433512 +0100
@@ -123,4 +123,4 @@
 
     done
 done) | sort -n
-echo "# THE LAST LINE IS NEVER READ!"
+echo "# THE LAST LINE IS NEVER READ"
diff -urN file-rc-0.8.12/update-rc.d file-rc-0.8.13/update-rc.d
--- file-rc-0.8.12/update-rc.d	2010-04-07 20:30:54.000000000 +0100
+++ file-rc-0.8.13/update-rc.d	2012-07-01 23:58:58.889861534 +0100
@@ -66,8 +66,11 @@
 }
 
 get_runlevels_for_sequence() {
-    local seq s i list
     seq=$1; shift
+    i=""
+    r=""
+    s=""
+    list=""
     for i in $*
     do
 	r=${i%%:*}
@@ -91,21 +94,6 @@
     return $false
 }
 
-remove_sequence() {
-    local outline
-    seq=$1; shift
-    outline=""
-    for i in $*
-    do
-	s=${i##*:}
-        if [ "$s" != "$seq" ]
-	then
-	    outline="$outline$i "
-	fi
-    done
-    echo "$outline"
-}
-
 get_shortest_sequence() {
     level=99
     for i in $*
@@ -116,39 +104,42 @@
     echo $level
 }
 
-print_config_line() {
-    if [ $startseq -eq $stopseq ]
-    then
-	NEW_START=`get_runlevels_for_sequence $startseq $STARTLIST`
-	NEW_STOP=`get_runlevels_for_sequence $stopseq $STOPLIST`
-	NEW_SEQ=$startseq
-	STARTLIST=`remove_sequence $startseq $STARTLIST`
-	STOPLIST=`remove_sequence $stopseq $STOPLIST`
-	startseq=`get_shortest_sequence $STARTLIST`
-	stopseq=`get_shortest_sequence $STOPLIST`
-    else
-	if [ $startseq -lt $stopseq ]
-	then
-	    NEW_START=`get_runlevels_for_sequence $startseq $STARTLIST`
-	    NEW_STOP="-"
-	    NEW_SEQ=$startseq
-	    STARTLIST=`remove_sequence $startseq $STARTLIST`
-	    startseq=`get_shortest_sequence $STARTLIST`
-	else
-	    NEW_START="-"
-	    NEW_STOP=`get_runlevels_for_sequence $stopseq $STOPLIST`
-	    NEW_SEQ=$stopseq
-	    STOPLIST=`remove_sequence $stopseq $STOPLIST`
-	    stopseq=`get_shortest_sequence $STOPLIST`
-	fi
+print_config_start_line() {
+    linebasename="$1"
+    linestartlist="$2"
+
+    NEW_START=""
+
+    if [ -n "$linestartlist" ]; then
+	linestartseq=`get_shortest_sequence $linestartlist`
+	NEW_START=`get_runlevels_for_sequence $linestartseq $linestartlist`
+	NEW_SEQ=$linestartseq
+
+	case "$NEW_SEQ" in
+	    ?) NEW_SEQ=0$NEW_SEQ ;;
+	esac
+	echo "$NEW_SEQ	-	$NEW_START		/etc/init.d/$linebasename" >> "$TMPFILE"
+	modified="1"
+    fi
+}
+
+print_config_stop_line() {
+    linebasename="$1"
+    linestoplist="$2"
+
+    NEW_STOP=""
+
+    if [ -n "$linestoplist" ]; then
+	linestopseq=`get_shortest_sequence $linestoplist`
+	NEW_STOP=`get_runlevels_for_sequence $linestopseq $linestoplist`
+	NEW_SEQ=$linestopseq
+
+	case "$NEW_SEQ" in
+	    ?) NEW_SEQ=0$NEW_SEQ ;;
+	esac
+	echo "$NEW_SEQ	$NEW_STOP	-		/etc/init.d/$linebasename" >> "$TMPFILE"
+	modified="1"
     fi
-    [ -z "$NEW_START" ] && NEW_START="-"
-    [ -z "$NEW_STOP" ] && NEW_STOP="-"
-    case "$NEW_SEQ" in
-	?) NEW_SEQ=0$NEW_SEQ ;;
-    esac
-    echo "$NEW_SEQ	$NEW_STOP	$NEW_START		/etc/init.d/$basename" >> "$TMPFILE"
-    modified="1"
 }
 
 do_while=1
@@ -212,52 +203,265 @@
     fi
 fi
 
+insserv_find_internal() {
+    OLDIFS="$IFS"
+    IFS=:
+
+    echo "$1" | while read IN_ACTION IN_SEQUENCE IN_LEVELS IN_BASENAME
+    do
+	if [ "$IN_BASENAME" = "$2" ]; then
+	    if [ "$IN_ACTION" = "S" ]; then
+		echo "START_SORT_NO=\"${IN_SEQUENCE}\""
+		echo "STARTLEVELS=\"${IN_LEVELS}\""
+	    elif [ "$IN_ACTION" = "K" ]; then
+		IN_FOUND="true"
+		echo "STOP_SORT_NO=\"${IN_SEQUENCE}\""
+		echo "STOPLEVELS=\"${IN_LEVELS}\""
+	    fi
+	fi
+    done
+    IFS="$OLDIFS"
+}
+
+insserv_find() {
+    idata=$(insserv_find_internal "$1" "$2")
+    if [ -n "$idata" ]; then
+	OLDIFS="$IFS"
+	IFS="
+"
+	for line in $(echo $idata); do
+	    eval "$line"
+	done
+	IFS="$OLDIFS"
+	return $true
+    fi
+    return $false;
+}
+
+create_lock() {
+    # wait for any lock to vanish
+    i=0
+    while [ -f "$LOCKFILE" ]
+    do
+	read pid < "$LOCKFILE"
+	if ! kill -s 0 $pid > /dev/null 2>&1
+	then
+            remove_lock
+            break
+	fi
+	if [ "$i" -gt "5" ]
+	then
+            echo "Process no. '$pid' is locking the configuration database. Terminating." >&2
+            exit 1
+	fi
+	sleep 2
+	i=$(($i + 1))
+    done
+
+    # lock the configuration file
+    echo "$$" > "$LOCKFILE"
+}
 
-cmd_already_there() {
-    local CMD
+remove_lock() {
+    rm -f "$LOCKFILE"
+}
+
+update_config() {
+    updateaction="$1"
+    updatebasename="$2"
+    startlist="$3"
+    stoplist="$4"
+    rm -f $TMPFILE
+    touch $TMPFILE
+
+    SORT_NO=0
+    if [ -n "$stoplist" ]; then
+	stopseq=`get_shortest_sequence $stoplist`
+    fi
+    if [ -n "$startlist" ]; then
+	startseq=`get_shortest_sequence $startlist`
+    fi
+    stopseen=0
+    startseen=0
     while read LINE
     do
 	case $LINE in
-	    \#* | "" ) continue
+	    \#\ THE\ LAST\ LINE\ IS\ NEVER\ READ* )
+	    # remove this "last" line and add it at the end of runlevel.conf
+		continue
+		;;
+	    \#* | "" )
+		echo "$LINE" >> "$TMPFILE"
+		continue
+		;;
 	esac
+
 	set -- $LINE
-	CMD="$4"
-	[ "$CMD" = "/etc/init.d/$basename" ] && return 0
+	SORT_NO="$1"; STOP="$2"; START="$3"; CMD="$4"
+
+	if [ "$updateaction" = "add" ]; then
+	    if [ -n "$stoplist" ]; then
+		if [ $stopseen -eq 0 ]; then
+		    if [ $SORT_NO -gt $stopseq ]; then
+			print_config_stop_line "$updatebasename" "$stoplist"
+			stopseen="1"
+		    fi
+		fi
+	    fi
+	    if [ -n "$startlist" ]; then
+		if [ $startseen -eq 0 ]; then
+		    if [ $SORT_NO -gt $startseq ]; then
+			print_config_start_line "$updatebasename" "$startlist"
+			startseen="1"
+		    fi
+		fi
+	    fi
+	fi
+
+	if [ "$CMD" != "/etc/init.d/$updatebasename" ]
+	then
+	    case "$SORT_NO" in
+		?) SORT_NO=0$SORT_NO
+		    modified="1"
+		    ;;
+	    esac
+	    echo "$SORT_NO	$STOP	$START		$CMD" >> "$TMPFILE"
+	elif [ "$updateaction" = "remove" ]
+	then
+	    # Remove by not echoing the line.
+	    modified="1"
+	fi
+
     done < "$CFGFILE"
-    return 1
+
+    if [ "$updateaction" = "add" ]; then
+	if [ -n "$stoplist" ]; then
+	    if [ $stopseen -eq 0 ]; then
+		print_config_stop_line "$updatebasename" "$stoplist"
+		stopseen="1"
+	    fi
+	fi
+	if [ -n "$startlist" ]; then
+	    if [ $startseen -eq 0 ]; then
+		print_config_start_line "$updatebasename" "$startlist"
+		startseen="1"
+	    fi
+	fi
+    fi
+
+    echo '# THE LAST LINE IS NEVER READ' >> "$TMPFILE"
+
+    if [ -z "$modified" ]
+    then
+	echo "Nothing to do."
+	rm -f "$TMPFILE"
+    else
+	if [ $opt_simulate -eq 0 ]; then
+	    umask=022
+	    mv "$TMPFILE" "$CFGFILE"
+	else
+	    echo "$TMPFILE not installed as $CFGFILE"
+	fi
+    fi
 }
 
+list_scripts() {
+    while read LINE
+    do
+	case $LINE in
+	    \#\ THE\ LAST\ LINE\ IS\ NEVER\ READ* )
+		continue
+		;;
+	    \#* | "" )
+		continue
+		;;
+	esac
+	set -- $LINE
+	SORT_NO="$1"; STOP="$2"; START="$3"; CMD="$4"
+	if [ -x "$CMD" ]; then
+	    echo $(basename "$CMD")
+	fi
+    done < "$CFGFILE"
+}
+
+action="$1"
+
+# Update existing scripts with insserv info
+if [ -x /sbin/insserv ]; then
+    in_data="$(/sbin/insserv -s 2>/dev/null)"
+
+    case "$action" in
+	defaults|add|remove|start|stop)
+	    create_lock
+	    for script in $(list_scripts | sort | uniq); do
+		START_SORT_NO=
+		STARTLEVELS=
+		STOP_SORT_NO=
+		STOPLEVELS=
+		if insserv_find "$in_data" "$script"; then
+		    STARTLIST=
+		    STOPLIST=
+		    for lev in $STARTLEVELS; do
+			STARTLIST="$STARTLIST$lev:$START_SORT_NO "
+		    done
+		    for lev in $STOPLEVELS; do
+			STOPLIST="$STOPLIST$lev:$STOP_SORT_NO "
+		    done
+		    update_config add "$script" "$STARTLIST" "$STOPLIST"
+		fi
+	    done
+	    remove_lock
+	    ;;
+    esac
+fi
+
+START_SORT_NO=
+STARTLEVELS=
+STOP_SORT_NO=
+STOPLEVELS=
+if [ -x /sbin/insserv ] && insserv_find "$in_data" "$basename"; then
+    IN_FOUND="true"
+else
+    IN_FOUND="false"
+fi
 
-START_SORT_NO=""
-STOP_SORT_NO=""
-STARTLEVELS=""
-STOPLEVELS=""
+if [ "$IN_FOUND" = "true" ]; then
+    echo "update-rc.d (file-rc) using dependency based boot sequencing"
+else
+    echo "update-rc.d (file-rc) using static boot sequencing (WARNING)"
+fi
 
 STARTLIST=
 STOPLIST=
-action="$1"
 case "$action" in
     defaults)
-	STARTLEVELS="2 3 4 5"
-	STOPLEVELS="0 1 6"
-	case "$#" in
-	    "1")
-		START_SORT_NO="20"
-		STOP_SORT_NO="20"
-		;;
-	    "2")
-		START_SORT_NO="$2"
-		STOP_SORT_NO="$2"
-		;;
-	    "3")
-		START_SORT_NO="$2"
-		STOP_SORT_NO="$3"
-		;;
-	esac
+	if [ "$IN_FOUND" = "false" ]; then
+	    STARTLEVELS="2 3 4 5"
+	    STOPLEVELS="0 1 6"
+	    case "$#" in
+		"1")
+		    START_SORT_NO="20"
+		    STOP_SORT_NO="20"
+		    ;;
+		"2")
+		    START_SORT_NO="$2"
+		    STOP_SORT_NO="$2"
+		    ;;
+		"3")
+		    START_SORT_NO="$2"
+		    STOP_SORT_NO="$3"
+		    ;;
+	    esac
+	fi
 
-	if ! is_valid_sequence $START_SORT_NO || ! is_valid_sequence $STOP_SORT_NO
+	if [ -n "$START_SORT_NO" ] && ! is_valid_sequence "$START_SORT_NO"
+	then
+	    echo "Invalid sequence $START_SORT_NO."
+	    exit 1
+	fi
+	if [ -n "$STOP_SORT_NO" ] && ! is_valid_sequence "$STOP_SORT_NO"
 	then
-	    echo "Invalid sequence $START_SORT_NO or $STOP_SORT_NO."
+	    echo "Invalid sequence $STOP_SORT_NO."
 	    exit 1
 	fi
 	for lev in $STARTLEVELS; do
@@ -266,178 +470,83 @@
 	for lev in $STOPLEVELS; do
 	    STOPLIST="$STOPLIST$lev:$STOP_SORT_NO "
 	done
-	action=add
+	create_lock
+	update_config add "$basename" "$STARTLIST" "$STOPLIST"
+	remove_lock
 	;;
     remove)
 	START_SORT_NO="*"
 	STOP_SORT_NO="*"
+	create_lock
+	update_config remove "$basename" "$STARTLIST" "$STOPLIST"
+	remove_lock
 	;;
     start|stop)
+	if [ "$IN_FOUND" = "false" ]; then
 	# Loop over the remaining arguments
-	while [ $# -gt 0 ]
-	do
- 	    if [ $# -gt 2 ]
- 	    then
- 		type="$1"; shift
- 		seq="$1"; shift
- 		levels=
-		if [ "$type" != "start" -a "$type" != "stop" ]
-		then
-		    echo "Invalid type $type."
-		    exit 1
-		fi
- 		if ! is_valid_sequence $seq
+	    while [ $# -gt 0 ]
+	    do
+ 		if [ $# -gt 2 ]
  		then
- 		    echo "Invalid sequence $seq."
- 		    exit 1
- 		fi
- 		while [ $# -gt 0 -a "$1" != "." ]
- 		do
-		    if ! is_valid_runlevel $1
+ 		    type="$1"; shift
+ 		    seq="$1"; shift
+ 		    levels=
+		    if [ "$type" != "start" -a "$type" != "stop" ]
 		    then
-			echo "Invalid runlevel $1."
+			echo "Invalid type $type."
 			exit 1
 		    fi
- 		    levels="$levels$1 "; shift
- 		done
- 		if [ $# -gt 0 -a "$1" = "." ]
- 		then
- 		    shift
+ 		    if ! is_valid_sequence $seq
+ 		    then
+ 			echo "Invalid sequence $seq."
+ 			exit 1
+ 		    fi
+ 		    while [ $# -gt 0 -a "$1" != "." ]
+ 		    do
+			if ! is_valid_runlevel $1
+			then
+			    echo "Invalid runlevel $1."
+			    exit 1
+			fi
+ 			levels="$levels$1 "; shift
+ 		    done
+ 		    if [ $# -gt 0 -a "$1" = "." ]
+ 		    then
+ 			shift
+ 		    fi
+		    case "$type" in
+			"start")
+			    for lev in $levels; do
+				STARTLIST="$STARTLIST$lev:$seq "
+			    done
+			    ;;
+			"stop")
+			    for lev in $levels; do
+				STOPLIST="$STOPLIST$lev:$seq "
+			    done
+			    ;;
+		    esac
+ 		else
+ 		    echo "Too few arguments."
+ 		    print_usage
+ 		    exit 1
  		fi
-		case "$type" in
-		"start")
-		    for lev in $levels; do
-			STARTLIST="$STARTLIST$lev:$seq "
-		    done
-		    ;;
-		"stop")
-		    for lev in $levels; do
-			STOPLIST="$STOPLIST$lev:$seq "
-		    done
-		    ;;
-		esac
- 	    else
- 		echo "Too few arguments."
- 		print_usage
- 		exit 1
- 	    fi
-	done
-	action=add
+	    done
+	else
+	    for lev in $STARTLEVELS; do
+		STARTLIST="$STARTLIST$lev:$START_SORT_NO "
+	    done
+	    for lev in $STOPLEVELS; do
+		STOPLIST="$STOPLIST$lev:$STOP_SORT_NO "
+	    done
+	fi
+	create_lock
+	update_config add "$basename" "$STARTLIST" "$STOPLIST"
+	remove_lock
 	;;
     *)
 	print_usage
 	;;
 esac
 
-remove_lock() {
-    rm -f "$LOCKFILE"
-}
-
-  # wait for any lock to vanish
-i=0
-while [ -f "$LOCKFILE" ]
-do
-    read pid < "$LOCKFILE"
-    if ! kill -s 0 $pid > /dev/null 2>&1
-    then
-        remove_lock
-        break
-    fi
-    if [ "$i" -gt "5" ]
-    then
-        echo "Process no. '$pid' is locking the configuration database. Terminating." >&2
-        exit 1
-    fi
-    sleep 2
-    i=$(($i + 1))
-done
-
-  # lock the configuration file
-echo "$$" > "$LOCKFILE"
-
-if [ $opt_force -eq 0 -a "$action" != "remove" ] && cmd_already_there 
-then
-    echo "$basename already in $CFGFILE: No change."
-    remove_lock
-    exit 0
-fi
-
-skip=""
-rm -f $TMPFILE
-touch $TMPFILE
-
-stopseq=`get_shortest_sequence $STOPLIST`
-startseq=`get_shortest_sequence $STARTLIST`
-SORT_NO=0
-seen=0
-while read LINE
-do
-    remove=0
-
-    case $LINE in
-	\#\ THE\ LAST\ LINE\ IS\ NEVER\ READ* )
-	    # remove this "last" line and add it at the end of runlevel.conf
-	    continue
-	    ;;
-	\#* | "" )
-	    echo "$LINE" >> "$TMPFILE"
-	    continue
-	    ;;
-    esac
-
-    set -- $LINE
-    SORT_NO="$1"; STOP="$2"; START="$3"; CMD="$4"
-
-    if [ "$CMD" = "/etc/init.d/$basename" ] 
-    then
-	[ "$action" = "remove" ] && remove=1
-	[ "$action" = "add" -a $opt_force -eq 1 ] && remove=1
-	[ $opt_force -eq 0 ] && seen=1
-    fi
-
-    if [ $seen -eq 0 ]
-    then
-	if [ $SORT_NO -gt $stopseq -o $SORT_NO -gt $startseq ]
-	then
-	    print_config_line
-	fi
-    fi
-
-    if [ $remove -ne 1 ]
-    then
-	case "$SORT_NO" in
-	    ?) SORT_NO=0$SORT_NO
-	       modified="1"
-	       ;;
-	esac
-	echo "$SORT_NO	$STOP	$START		$CMD" >> "$TMPFILE"
-    else
-	modified="1"
-    fi
-
-done < "$CFGFILE"
-
-if [ $seen -eq 0 ]
-then
-    while [ -n "$STARTLIST" -o  -n "$STOPLIST" ]
-    do
-	print_config_line
-    done
-fi
-echo '# THE LAST LINE IS NEVER READ' >> "$TMPFILE"
-
-remove_lock
-
-if [ -z "$modified" ]
-then
-    echo "Nothing to do."
-    rm -f "$TMPFILE"
-else
-    if [ $opt_simulate -eq 0 ]; then
-	umask=022
-	mv "$TMPFILE" "$CFGFILE"
-    else
-	echo "$TMPFILE not installed as $CFGFILE"
-    fi
-fi
 exit 0

Reply via email to