[Pkg-sysvinit-devel] [PATCH 3/4] update-rc.d: add runlevel link migration interface

Kel Modderman kel at otaku42.de
Thu Sep 18 08:51:28 UTC 2008


When run with the from ... to ... options, update-rc.d can migrate the runlevel
links for a script from old defaults to new defaults while preserving any
local modifications.

It is intended that this be used only in maintainer scripts of packages wishing
to change the runlevel link configuration for a service script while preserving
locally modified link configurations.

Real world example
==================
Package `hotkey-setup' used default dh_installinit settings up until package
version 0.1-17.2. In all of those package versions, the dh_installinit
autogenerated section of hotkey-setup.postinst contained the update-rc.d
command: "update-rc.d hotkey-setup defaults"

In hotkey-setup package version 0.1-17.2, the postinst maintainer script looks
like:
===
# Remove symlinks to script to have them reinserted by debhelper
# without the shutdown and reboot links; this init script does not
# need them.
if dpkg --compare-versions "$2" lt "0.1-17.2"; then
	update-rc.d -f hotkey-setup remove
fi

#DEBHELPER#
===

Installation of this version of hotkey-setup would force the purge of existing
runlevel links for /etc/init.d/hotkey-setup, so that the new dh_installinit
autogenerated update-rc.d command could take effect. This practise does not
preserve administrator modified runlevel configuration and is therefore prone
to error, policy violation bugs and end user complaint.

Using the "from ... to ..." feature, the same result could have been achieved
with a postinst snippet similar to:
===
# Drop shutdown link from runlevels 0 and 6, this package does not require them
if dpkg --compare-versions "$2" lt "0.1-17.2"; then
	update-rc.d hotkey-setup from defaults to start 20 2 3 4 5 . stop 20 1 .
fi

#DEBHELPER#
===

See also: http://lists.debian.org/debian-devel/2008/01/msg00007.html


Examples
========
# Establish initial runlevel configuration
$ update-rc.d hotkey-setup defaults
 Adding system startup for /etc/init.d/hotkey-setup ...
   /etc/rc0.d/K20hotkey-setup -> ../init.d/hotkey-setup
   /etc/rc1.d/K20hotkey-setup -> ../init.d/hotkey-setup
   /etc/rc6.d/K20hotkey-setup -> ../init.d/hotkey-setup
   /etc/rc2.d/S20hotkey-setup -> ../init.d/hotkey-setup
   /etc/rc3.d/S20hotkey-setup -> ../init.d/hotkey-setup
   /etc/rc4.d/S20hotkey-setup -> ../init.d/hotkey-setup
   /etc/rc5.d/S20hotkey-setup -> ../init.d/hotkey-setup

/
`-- etc
    |-- init.d
    |   `-- hotkey-setup
    |-- rc0.d
    |   `-- K20hotkey-setup -> ../init.d/hotkey-setup
    |-- rc1.d
    |   `-- K20hotkey-setup -> ../init.d/hotkey-setup
    |-- rc2.d
    |   `-- S20hotkey-setup -> ../init.d/hotkey-setup
    |-- rc3.d
    |   `-- S20hotkey-setup -> ../init.d/hotkey-setup
    |-- rc4.d
    |   `-- S20hotkey-setup -> ../init.d/hotkey-setup
    |-- rc5.d
    |   `-- S20hotkey-setup -> ../init.d/hotkey-setup
    |-- rc6.d
    |   `-- K20hotkey-setup -> ../init.d/hotkey-setup
    `-- rcS.d

# Modify default runlevel link to scheme without link in runlevel 0 and 6
$ update-rc.d hotkey-setup from defaults to start 20 2 3 4 5 . stop 20 1 .
 Preparing to modify system startup links for /etc/init.d/hotkey-setup ...
 Modifying system startup links for /etc/init.d/hotkey-setup ...
 Removing any system startup links for /etc/init.d/hotkey-setup ...
   /etc/rc0.d/K20hotkey-setup
   /etc/rc1.d/K20hotkey-setup
   /etc/rc2.d/S20hotkey-setup
   /etc/rc3.d/S20hotkey-setup
   /etc/rc4.d/S20hotkey-setup
   /etc/rc5.d/S20hotkey-setup
   /etc/rc6.d/K20hotkey-setup
 Adding system startup for /etc/init.d/hotkey-setup ...
   /etc/rc1.d/K20hotkey-setup -> ../init.d/hotkey-setup
   /etc/rc2.d/S20hotkey-setup -> ../init.d/hotkey-setup
   /etc/rc3.d/S20hotkey-setup -> ../init.d/hotkey-setup
   /etc/rc4.d/S20hotkey-setup -> ../init.d/hotkey-setup
   /etc/rc5.d/S20hotkey-setup -> ../init.d/hotkey-setup

/
`-- etc
    |-- init.d
    |   `-- hotkey-setup
    |-- rc0.d
    |-- rc1.d
    |   `-- K20hotkey-setup -> ../init.d/hotkey-setup
    |-- rc2.d
    |   `-- S20hotkey-setup -> ../init.d/hotkey-setup
    |-- rc3.d
    |   `-- S20hotkey-setup -> ../init.d/hotkey-setup
    |-- rc4.d
    |   `-- S20hotkey-setup -> ../init.d/hotkey-setup
    |-- rc5.d
    |   `-- S20hotkey-setup -> ../init.d/hotkey-setup
    |-- rc6.d
    `-- rcS.d

# The admin decides for whatever reason to remove these links
$ update-rc.d -f hotkey-setup remove
 Removing any system startup links for /etc/init.d/hotkey-setup ...
   /etc/rc1.d/K20hotkey-setup
   /etc/rc2.d/S20hotkey-setup
   /etc/rc3.d/S20hotkey-setup
   /etc/rc4.d/S20hotkey-setup
   /etc/rc5.d/S20hotkey-setup

# Try the same modifcation command as before, but no links exist this time
$ update-rc.d hotkey-setup from defaults to start 20 2 3 4 5 . stop 20 1 .
 System startup links for /etc/init.d/hotkey-setup do not exist.

# Restablish default configuration
$ update-rc.d hotkey-setup defaults
 Adding system startup for /etc/init.d/hotkey-setup ...
   /etc/rc0.d/K20hotkey-setup -> ../init.d/hotkey-setup
   /etc/rc1.d/K20hotkey-setup -> ../init.d/hotkey-setup
   /etc/rc6.d/K20hotkey-setup -> ../init.d/hotkey-setup
   /etc/rc2.d/S20hotkey-setup -> ../init.d/hotkey-setup
   /etc/rc3.d/S20hotkey-setup -> ../init.d/hotkey-setup
   /etc/rc4.d/S20hotkey-setup -> ../init.d/hotkey-setup
   /etc/rc5.d/S20hotkey-setup -> ../init.d/hotkey-setup

# Admin manually modifies runlevel configuration
$ mv /etc/rc5.d/S20hotkey-setup /etc/rc5.d/K20hotkey-setup

# Try the same modifcation command as before, showing how modified runlevel
# configuration is preserved
$ update-rc.d hotkey-setup from defaults to start 20 2 3 4 5 . stop 20 1 .
 Preparing to modify system startup links for /etc/init.d/hotkey-setup ...
update-rc.d: warning: /etc/rc5.d/S20hotkey-setup is not a symbolic link
 Preserving locally modified system startup links for /etc/init.d/hotkey-setup ...

/
`-- etc
    |-- init.d
    |   `-- hotkey-setup
    |-- rc0.d
    |   `-- K20hotkey-setup -> ../init.d/hotkey-setup
    |-- rc1.d
    |   `-- K20hotkey-setup -> ../init.d/hotkey-setup
    |-- rc2.d
    |   `-- S20hotkey-setup -> ../init.d/hotkey-setup
    |-- rc3.d
    |   `-- S20hotkey-setup -> ../init.d/hotkey-setup
    |-- rc4.d
    |   `-- S20hotkey-setup -> ../init.d/hotkey-setup
    |-- rc5.d
    |   `-- K20hotkey-setup -> ../init.d/hotkey-setup
    |-- rc6.d
    |   `-- K20hotkey-setup -> ../init.d/hotkey-setup
    `-- rcS.d

---
--- a/debian/sysv-rc/sbin/update-rc.d
+++ b/debian/sysv-rc/sbin/update-rc.d
@@ -19,6 +19,7 @@
 usage: update-rc.d [-d <path>] [-n] [-f] <basename> remove
        update-rc.d [-d <path>] [-n] <basename> defaults [NN | SS KK]
        update-rc.d [-d <path>] [-n] <basename> start|stop NN runlvl [runlvl] [...] .
+       update-rc.d [-d <path>] [-n] <basename> from [...] to [...]
 		-n: not really
 		-f: force
 		-d: path to alternate /
@@ -75,6 +76,7 @@
 
 $_ = $ARGV[0];
 if    (/^remove$/)       { &checklinks ("remove"); }
+elsif (/^from$/)         { &fromto (@ARGV); &makelinks; }
 elsif (/^defaults$/)     { &defaults (@ARGV); &makelinks; }
 elsif (/^(start|stop)$/) { &startstop (@ARGV); &makelinks; }
 else                     { &usage; }
@@ -88,7 +90,9 @@
 sub is_link () {
     my ($op, $fn, $bn) = @_;
     if (! -l $fn) {
-	print STDERR "update-rc.d: warning: $fn is not a symbolic link\n";
+	if ($op ne 'quiet') {
+	    print STDERR "update-rc.d: warning: $fn is not a symbolic link\n";
+	}
 	return 0;
     } else {
 	my $linkdst = readlink ($fn);
@@ -96,7 +100,9 @@
 	    die ("update-rc.d: error reading symbolic link: $!\n");
 	}
 	if (($linkdst ne "../init.d/$bn") && ($linkdst ne "$initd/$bn")) {
-	    print STDERR "update-rc.d: warning: $fn is not a link to ../init.d/$bn or $initd/$bn\n";
+	    if ($op ne 'quiet') {
+		print STDERR "update-rc.d: warning: $fn is not a link to ../init.d/$bn or $initd/$bn\n";
+	    }
 	    return 0;
 	}
     }
@@ -168,6 +174,59 @@
 }
 
 
+# Process the arguments after the "from" keyword.
+
+sub fromto {
+    my @argv = @_;
+    my ($defaults, $abort) = (0, 0);
+    my ($i, $islink, @from, @to);
+
+    if (!&checklinks) {
+	print " System startup links for $initd/$bn do not exist.\n";
+	exit (0);
+    }
+
+    while ($#argv >= 0 && shift @argv) {
+	if    ($argv[0] eq 'to')       { @to = @argv; last; }
+	elsif ($argv[0] eq 'defaults') { $defaults++ }
+	push(@from, $argv[0]);
+    }
+
+    &usage ("expected 'to' keyword") if ($to[0] ne 'to');
+    shift @to;
+
+    if ($from[0] eq 'defaults') { &defaults  (@from); }
+    else                        { &startstop (@from); }
+
+    foreach $i (0..$#startlinks) {
+	next if !$startlinks[$i];
+	$islink = &is_link ('quiet', "$etcd$i.d/$startlinks[$i]$bn", $bn);
+	if (!$islink) { $abort++; }
+    }
+
+    foreach $i (0..$#stoplinks) {
+	next if !$stoplinks[$i];
+	$islink = &is_link ('quiet', "$etcd$i.d/$stoplinks[$i]$bn", $bn);
+	if (!$islink) { $abort++; }
+    }
+
+    @startlinks = @stoplinks = ();
+
+    if ($abort) {
+	print " Preserving locally modified system startup links for $initd/$bn ...\n";
+	exit (0);
+    }
+
+    if ($to[0] eq 'defaults') { &defaults  (@to); }
+    else                      { &startstop (@to); }
+
+    print " Migrating default system startup links for $initd/$bn ...\n";
+
+    &checklinks ("remove");
+
+    1;
+}
+
 # Process the arguments after the "defaults" keyword.
 
 sub defaults {
@@ -239,7 +298,7 @@
 	print " System startup links for $initd/$bn already exist.\n";
 	exit (0);
     }
-    print " Adding system startup for $initd/$bn ...\n";
+    print " Adding system startup links for $initd/$bn ...\n";
 
     # nice unreadable perl mess :)
 
--- a/debian/sysv-rc/man8/update-rc.d.8
+++ b/debian/sysv-rc/man8/update-rc.d.8
@@ -26,6 +26,13 @@
 .BR start | stop
 .IR "NN runlevel" " [" runlevel "]..."
 .BR . " ..."
+.HP
+.B update-rc.d
+.RI [ -d " path " ]
+.RI [ -n ]
+.I name
+.BR from " defaults|start|stop ... "
+.BR to " defaults|start|stop ... "
 .SH DESCRIPTION
 .B update-rc.d
 updates the System V style init script links
@@ -178,7 +185,7 @@
 must exist before
 .B update-rc.d
 is run to create the links.
-.SH REMOVING SCRIPTS
+.SH REMOVING INIT SCRIPT LINKS
 When invoked with the
 .I remove
 option, update-rc.d removes any links in the
@@ -200,6 +207,32 @@
 directories that are not symbolic links to the script
 .BI /etc/init.d/ name
 will be left untouched.
+.SH MODIFYING INIT SCRIPT LINKS
+When run with the
+.BR from " ... " to " ... "
+options,
+.B update-rc.d
+modifies existing runlevel links for the script
+.BR /etc/init.d/ \fIname\fR.
+.P
+If the current runlevel link configuration for
+.BR /etc/init.d/ \fIname\fR
+could be recreated as if
+.B update-rc.d
+had been called with only the arguments between the
+.B from
+and
+.B to
+keywords, the current links will be removed and replaced with new
+links as if
+.B update-rc.d
+had been called with only the arguments after the
+.B to
+keyword.
+.P
+It is intended that this be used only in maintainer scripts of
+packages wishing to change the runlevel link configuration for a
+service script while preserving locally modified link configurations.
 
 .SH OPTIONS
 .TP
@@ -262,6 +295,11 @@
 .B "   update-rc.d -f foobar remove"
 .B "   update-rc.d foobar stop 45 S ."
 .fi
+Example of a command for modifying existing links for a script that was
+initially installed using the \fIdefaults\fR argument:
+.nf
+.B "   update-rc.d foobar from defaults to start 20 2 3 4 5 . stop 20 1 ."
+.fi
 
 .SH BUGS
 See http://bugs.debian.org/sysv-rc.
---



More information about the Pkg-sysvinit-devel mailing list