Subject: [PATCH 3/5] Fix a bug where init scripts not being registered were not checked

From: Raphael Geissert <[email-masked]>
Date: Tue, 16 Jun 2009 14:44:50 -0500

Some packages do not register their init scripts on the maintainer
scripts, leading to lintian completely ignoring them when performing
other checks.
---
 checks/init.d                                      |  193 ++++++++++----------
 .../debian/debian/install                          |    1 +
 t/tests/init.d-script-registration/debian/foo.in   |   14 ++
 t/tests/init.d-script-registration/desc            |    5 +
 t/tests/init.d-script-registration/tags            |    2 +
 5 files changed, 122 insertions(+), 93 deletions(-)
 create mode 100644 t/tests/init.d-script-registration/debian/debian/install
 create mode 100644 t/tests/init.d-script-registration/debian/foo.in
 create mode 100644 t/tests/init.d-script-registration/desc
 create mode 100644 t/tests/init.d-script-registration/tags

diff --git a/checks/init.d b/checks/init.d
index 97bb780..f134ed0 100644
--- a/checks/init.d
+++ b/checks/init.d
@@ -151,116 +151,123 @@ for (keys %initd_postinst) {
     # check if file exists in package
     my $initd_file = "init.d/$_";
     if (-f $initd_file) {
-	# yes! check it...
-	open(IN, '<', $initd_file)
-	    or fail("cannot open init.d file $initd_file: $!");
-	my (%tag, %lsb);
-	while (defined(my $l = <IN>)) {
-	    if ($. eq 1 && $l =~ m,^#!\s*(/usr/[^\s]+),) {
-		tag "init.d-script-uses-usr-interpreter", "/etc/init.d/$_ $1";
-	    }
-	    if ($l =~ m/^\#\#\# BEGIN INIT INFO/) {
-		if ($lsb{BEGIN}) {
-		    tag "init.d-script-has-duplicate-lsb-section", "/etc/init.d/$_";
-		    next;
-		}
-		$lsb{BEGIN} = 1;
-		my $last;
+	checkinit($initd_file);
+    } else {
+	tag "init.d-script-not-included-in-package", "/etc/init.d/$_";
+    }
+}
 
-		# We have an LSB keyword section.  Parse it and save the data
-		# in %lsb for analysis.
-		while (defined(my $l = <IN>)) {
-		    if ($l =~ /^\#\#\# END INIT INFO/) {
-			$lsb{END} = 1;
-			last;
-		    } elsif ($l !~ /^\#/) {
-			tag "init.d-script-has-unterminated-lsb-section", "/etc/init.d/$_:$.";
-			last;
-		    } elsif ($l =~ /^\# ([a-zA-Z-]+):\s*(.*?)\s*$/) {
-			my $keyword = lc $1;
-			my $value = $2;
-			tag "init.d-script-has-duplicate-lsb-keyword", "/etc/init.d/$_:$. $keyword"
-			    if (defined $lsb{$keyword});
-			tag "init.d-script-has-unknown-lsb-keyword", "/etc/init.d/$_:$. $keyword"
-			    unless (defined ($lsb_keywords{$keyword}) || $keyword =~ /^x-/);
-			$lsb{$keyword} = $value || '';
-			$last = $keyword;
-		    } elsif ($l =~ /^\#(\t|  )/ && $last eq 'description') {
-			my $value = $l;
-			$value =~ s/^\#\s*//;
-			$lsb{description} .= ' ' . $value;
-		    } else {
-			tag "init.d-script-has-bad-lsb-line", "/etc/init.d/$_:$.";
-		    }
-		}
-	    }
+# files actually installed in /etc/init.d should match our list :-)
+opendir(INITD, "init.d") or fail("cannot read init.d directory: $!");
+for (readdir(INITD)) {
+    next if $_ eq '.' || $_ eq '..';
+    unless ($initd_postinst{$_}) {
+	tag "script-in-etc-init.d-not-registered-via-update-rc.d", "/etc/init.d/$_";
+	checkinit("init.d/$_");
+    }
+}
+closedir(INITD);
+
+}
 
-	    while ($l =~ s/^[^#]*?(start|stop|restart|force-reload)//o) {
-		$tag{$1} = 1;
+sub checkinit {
+    my ($initd_file) = @_;
+    # yes! check it...
+    open(IN, '<', $initd_file)
+	or fail("cannot open init.d file $initd_file: $!");
+    my (%tag, %lsb);
+    while (defined(my $l = <IN>)) {
+	if ($. eq 1 && $l =~ m,^#!\s*(/usr/[^\s]+),) {
+	    tag "init.d-script-uses-usr-interpreter", "/etc/init.d/$_ $1";
+	}
+	if ($l =~ m/^\#\#\# BEGIN INIT INFO/) {
+	    if ($lsb{BEGIN}) {
+		tag "init.d-script-has-duplicate-lsb-section", "/etc/init.d/$_";
+		next;
 	    }
-        }
-	close(IN);
+	    $lsb{BEGIN} = 1;
+	    my $last;
 
-	# Make sure all of the required keywords are present.
-	if (not $lsb{BEGIN}) {
-	    tag "init.d-script-missing-lsb-section", "/etc/init.d/$_";
-	} else {
-	    for my $keyword (keys %lsb_keywords) {
-		if ($lsb_keywords{$keyword} && !defined $lsb{$keyword}) {
-		    if ($keyword eq 'short-description') {
-			tag "init.d-script-missing-lsb-short-description", "/etc/init.d/$_";
-		    } else {
-			tag "init.d-script-missing-lsb-keyword", "/etc/init.d/$_ $keyword";
-		    }
+	    # We have an LSB keyword section.  Parse it and save the data
+	    # in %lsb for analysis.
+	    while (defined(my $l = <IN>)) {
+		if ($l =~ /^\#\#\# END INIT INFO/) {
+		    $lsb{END} = 1;
+		    last;
+		} elsif ($l !~ /^\#/) {
+		    tag "init.d-script-has-unterminated-lsb-section", "/etc/init.d/$_:$.";
+		    last;
+		} elsif ($l =~ /^\# ([a-zA-Z-]+):\s*(.*?)\s*$/) {
+		    my $keyword = lc $1;
+		    my $value = $2;
+		    tag "init.d-script-has-duplicate-lsb-keyword", "/etc/init.d/$_:$. $keyword"
+			if (defined $lsb{$keyword});
+		    tag "init.d-script-has-unknown-lsb-keyword", "/etc/init.d/$_:$. $keyword"
+			unless (defined ($lsb_keywords{$keyword}) || $keyword =~ /^x-/);
+		    $lsb{$keyword} = $value || '';
+		    $last = $keyword;
+		} elsif ($l =~ /^\#(\t|  )/ && $last eq 'description') {
+		    my $value = $l;
+		    $value =~ s/^\#\s*//;
+		    $lsb{description} .= ' ' . $value;
+		} else {
+		    tag "init.d-script-has-bad-lsb-line", "/etc/init.d/$_:$.";
 		}
 	    }
 	}
 
-	# Check the runlevels.
-	my %start;
-	if ($lsb{'default-start'}) {
-	    for my $runlevel (split (/\s+/, $lsb{'default-start'})) {
-		if ($runlevel =~ /^[sS0-6]$/) {
-		    $start{lc $runlevel} = 1;
+	while ($l =~ s/^[^#]*?(start|stop|restart|force-reload)//o) {
+	    $tag{$1} = 1;
+	}
+    }
+    close(IN);
+
+    # Make sure all of the required keywords are present.
+    if (not $lsb{BEGIN}) {
+	tag "init.d-script-missing-lsb-section", "/etc/init.d/$_";
+    } else {
+	for my $keyword (keys %lsb_keywords) {
+	    if ($lsb_keywords{$keyword} && !defined $lsb{$keyword}) {
+		if ($keyword eq 'short-description') {
+		    tag "init.d-script-missing-lsb-short-description", "/etc/init.d/$_";
 		} else {
-		    tag "init.d-script-has-bad-start-runlevel", "/etc/init.d/$_ $runlevel";
+		    tag "init.d-script-missing-lsb-keyword", "/etc/init.d/$_ $keyword";
 		}
 	    }
 	}
-	if ($lsb{'default-stop'}) {
-	    for my $runlevel (split (/\s+/, $lsb{'default-stop'})) {
-		if ($runlevel =~ /^[sS0-6]$/) {
-		    if ($start{$runlevel}) {
-			tag "init.d-script-has-conflicting-start-stop", "/etc/init.d/$_ $runlevel";
-		    }
-		    if ($runlevel =~ /[sS]/) {
-			tag "init-d-script-stops-in-s-runlevel", "/etc/init.d/$_";
-		    }
-		} else {
-		    tag "init.d-script-has-bad-stop-runlevel", "/etc/init.d/$_ $runlevel";
+    }
+
+    # Check the runlevels.
+    my %start;
+    if ($lsb{'default-start'}) {
+	for my $runlevel (split (/\s+/, $lsb{'default-start'})) {
+	    if ($runlevel =~ /^[sS0-6]$/) {
+		$start{lc $runlevel} = 1;
+	    } else {
+		tag "init.d-script-has-bad-start-runlevel", "/etc/init.d/$_ $runlevel";
+	    }
+	}
+    }
+    if ($lsb{'default-stop'}) {
+	for my $runlevel (split (/\s+/, $lsb{'default-stop'})) {
+	    if ($runlevel =~ /^[sS0-6]$/) {
+		if ($start{$runlevel}) {
+		    tag "init.d-script-has-conflicting-start-stop", "/etc/init.d/$_ $runlevel";
 		}
+		if ($runlevel =~ /[sS]/) {
+		    tag "init-d-script-stops-in-s-runlevel", "/etc/init.d/$_";
+		}
+	    } else {
+		tag "init.d-script-has-bad-stop-runlevel", "/etc/init.d/$_ $runlevel";
 	    }
 	}
-
-	# all tags included in file?
-	$tag{'start'} or tag "init.d-script-does-not-implement-required-option", "/etc/init.d/$_ start";
-	$tag{'stop'} or tag "init.d-script-does-not-implement-required-option", "/etc/init.d/$_ stop";
-	$tag{'restart'} or tag "init.d-script-does-not-implement-required-option", "/etc/init.d/$_ restart";
-	$tag{'force-reload'} or tag "init.d-script-does-not-implement-required-option", "/etc/init.d/$_ force-reload";
-    } else {
-	tag "init.d-script-not-included-in-package", "/etc/init.d/$_";
     }
-}
-
-# files actually installed in /etc/init.d should match our list :-)
-opendir(INITD, "init.d") or fail("cannot read init.d directory: $!");
-for (readdir(INITD)) {
-    next if $_ eq '.' || $_ eq '..';
-    tag "script-in-etc-init.d-not-registered-via-update-rc.d", "/etc/init.d/$_"
-	unless $initd_postinst{$_};
-}
-closedir(INITD);
 
+    # all tags included in file?
+    $tag{'start'} or tag "init.d-script-does-not-implement-required-option", "/etc/init.d/$_ start";
+    $tag{'stop'} or tag "init.d-script-does-not-implement-required-option", "/etc/init.d/$_ stop";
+    $tag{'restart'} or tag "init.d-script-does-not-implement-required-option", "/etc/init.d/$_ restart";
+    $tag{'force-reload'} or tag "init.d-script-does-not-implement-required-option", "/etc/init.d/$_ force-reload";
 }
 
 1;
diff --git a/t/tests/init.d-script-registration/debian/debian/install b/t/tests/init.d-script-registration/debian/debian/install
new file mode 100644
index 0000000..57fadcb
--- /dev/null
+++ b/t/tests/init.d-script-registration/debian/debian/install
@@ -0,0 +1 @@
+foo.in /etc/init.d/
diff --git a/t/tests/init.d-script-registration/debian/foo.in b/t/tests/init.d-script-registration/debian/foo.in
new file mode 100644
index 0000000..735d88e
--- /dev/null
+++ b/t/tests/init.d-script-registration/debian/foo.in
@@ -0,0 +1,14 @@
+#!/bin/sh -e
+
+case "$1" in
+    start)
+    ;;
+    stop)
+    ;;
+    reload)
+    ;;
+    restart|force-reload)
+    ;;
+    *)
+    ;;
+esac
diff --git a/t/tests/init.d-script-registration/desc b/t/tests/init.d-script-registration/desc
new file mode 100644
index 0000000..4674ad2
--- /dev/null
+++ b/t/tests/init.d-script-registration/desc
@@ -0,0 +1,5 @@
+Testname: init.d-script-registration
+Sequence: 6000
+Version: 1.0
+Description: Test tags related to the registration of init scripts
+Test-For: init.d-script-missing-lsb-section
\ No newline at end of file
diff --git a/t/tests/init.d-script-registration/tags b/t/tests/init.d-script-registration/tags
new file mode 100644
index 0000000..3adac56
--- /dev/null
+++ b/t/tests/init.d-script-registration/tags
@@ -0,0 +1,2 @@
+W: init.d-script-registration: init.d-script-missing-lsb-section /etc/init.d/foo.in
+W: init.d-script-registration: script-in-etc-init.d-not-registered-via-update-rc.d /etc/init.d/foo.in
-- 
1.6.3.1