From 843c8721f195ff906263e0b5a6191b4c0b70aa85 Mon Sep 17 00:00:00 2001 From: Jay Larson Date: Sat, 28 Jul 2018 14:30:08 -0500 Subject: [PATCH] The following changes were made: * Configuration moved to new CONFIG directory to separate from usher * Made various improvements to most init scripts * Added dependency to perl for update-rc --- .../halt.default => CONFIG/etc/default/halt | 0 .../rcS.default => CONFIG/etc/default/rcS | 0 {SRC/initscripts => CONFIG/etc}/fstab | 0 {SRC/initscripts => CONFIG/etc}/modules.conf | 0 Makefile | 7 +- SNAP/usher | 16 - SRC/initscripts/Makefile | 30 +- SRC/initscripts/init-functions | 51 +- SRC/initscripts/init.d/checkfs | 60 +- SRC/initscripts/init.d/checkroot | 136 +++++ SRC/initscripts/init.d/cleanfs | 10 + SRC/initscripts/init.d/hwclock | 5 +- SRC/initscripts/init.d/mountfs | 25 +- SRC/initscripts/init.d/mountnetfs | 34 ++ SRC/initscripts/init.d/mountvirtfs | 2 +- SRC/initscripts/init.d/reboot | 2 +- SRC/initscripts/init.d/sendsignals | 2 +- SRC/initscripts/init.d/swap | 2 +- SRC/initscripts/init.d/sysctl | 2 +- SRC/initscripts/service | 11 + SRC/initscripts/update-rc | 559 ++++++++++++------ 21 files changed, 644 insertions(+), 310 deletions(-) rename SRC/initscripts/halt.default => CONFIG/etc/default/halt (100%) rename SRC/initscripts/rcS.default => CONFIG/etc/default/rcS (100%) rename {SRC/initscripts => CONFIG/etc}/fstab (100%) rename {SRC/initscripts => CONFIG/etc}/modules.conf (100%) mode change 100644 => 100755 SRC/initscripts/init-functions create mode 100755 SRC/initscripts/init.d/checkroot create mode 100755 SRC/initscripts/init.d/mountnetfs create mode 100755 SRC/initscripts/service diff --git a/SRC/initscripts/halt.default b/CONFIG/etc/default/halt similarity index 100% rename from SRC/initscripts/halt.default rename to CONFIG/etc/default/halt diff --git a/SRC/initscripts/rcS.default b/CONFIG/etc/default/rcS similarity index 100% rename from SRC/initscripts/rcS.default rename to CONFIG/etc/default/rcS diff --git a/SRC/initscripts/fstab b/CONFIG/etc/fstab similarity index 100% rename from SRC/initscripts/fstab rename to CONFIG/etc/fstab diff --git a/SRC/initscripts/modules.conf b/CONFIG/etc/modules.conf similarity index 100% rename from SRC/initscripts/modules.conf rename to CONFIG/etc/modules.conf diff --git a/Makefile b/Makefile index 23142ba..c015e25 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. -DEPENDS = dash,kmod,procps-ng,sysvinit +DEPENDS = dash,kmod,perl,procps-ng,sysvinit ARCH = x86_64 URL = http://snaplinux.org REPO = core @@ -18,7 +18,7 @@ DESC = This package supplies the core required init scripts for startup ARCHIVE := '' SRCDIR := $(PWD)/SRC/initscripts PATCHDIR := $(PWD)/SRC/patches -VERSION := 1.8-0 +VERSION := 1.9-0 include /usr/share/snap/Makefile.snaplinux @@ -35,5 +35,6 @@ clean: @rm -rvf $(ROOT) \ $(SNAPINFO) \ $(MANIFEST) \ - $(FILES) + $(FILES) \ + $(CONFIG) diff --git a/SNAP/usher b/SNAP/usher index 1140a91..7b3d049 100755 --- a/SNAP/usher +++ b/SNAP/usher @@ -8,22 +8,6 @@ case $1 in ;; postinst) update-rc required - - if [ ! -f /etc/fstab ]; then - cp /usr/share/initscripts/fstab /etc/fstab - fi - - if [ ! -f /etc/modules.conf ]; then - cp /usr/share/initscripts/modules.conf /etc/modules.conf - fi - - if [ ! -f /etc/default/halt ]; then - cp /usr/share/initscripts/halt.default /etc/default/halt - fi - - if [ ! -f /etc/default/rcS ]; then - cp /usr/share/initscripts/rcS.default /etc/default/rcS - fi ;; prerm) exit 0 diff --git a/SRC/initscripts/Makefile b/SRC/initscripts/Makefile index 326c2ee..b3a6eaa 100644 --- a/SRC/initscripts/Makefile +++ b/SRC/initscripts/Makefile @@ -1,34 +1,18 @@ dirs: - install -d -m 755 $(DESTDIR)/etc/default install -d -m 755 $(DESTDIR)/etc/init.d + install -d -m 755 $(DESTDIR)/etc/modprobe.d install -d -m 755 $(DESTDIR)/lib/lsb - install -d -m 755 $(DESTDIR)/usr/share/initscripts install -d -m 755 $(DESTDIR)/usr/share/man/man8 install -d -m 755 $(DESTDIR)/usr/sbin + for rl in S 0 1 2 3 4 5 6; do \ + install -d -m 755 $(DESTDIR)/etc/rc$$rl.d; \ + done files: - install -m 755 init.d/checkfs $(DESTDIR)/etc/init.d/checkfs - install -m 755 init.d/cleanfs $(DESTDIR)/etc/init.d/cleanfs - install -m 755 init.d/halt $(DESTDIR)/etc/init.d/halt - install -m 755 init.d/hostname $(DESTDIR)/etc/init.d/hostname - install -m 755 init.d/hwclock $(DESTDIR)/etc/init.d/hwclock - install -m 755 init.d/modules $(DESTDIR)/etc/init.d/modules - install -m 755 init.d/mountfs $(DESTDIR)/etc/init.d/mountfs - install -m 755 init.d/mountvirtfs $(DESTDIR)/etc/init.d/mountvirtfs - install -m 755 init.d/rc $(DESTDIR)/etc/init.d/rc - install -m 755 init.d/reboot $(DESTDIR)/etc/init.d/reboot - install -m 755 init.d/sendsignals $(DESTDIR)/etc/init.d/sendsignals - install -m 755 init.d/swap $(DESTDIR)/etc/init.d/swap - install -m 755 init.d/sysctl $(DESTDIR)/etc/init.d/sysctl + for f in init.d/*; do \ + install -m 755 $$f $(DESTDIR)/etc/init.d; \ + done install -m 755 init-functions $(DESTDIR)/lib/lsb/init-functions - install -m 644 fstab \ - $(DESTDIR)/usr/share/initscripts/fstab - install -m 644 halt.default \ - $(DESTDIR)/usr/share/initscripts/halt.default - install -m 644 modules.conf \ - $(DESTDIR)/usr/share/initscripts/modules.conf - install -m 644 rcS.default \ - $(DESTDIR)/usr/share/initscripts/rcS.default install -m 755 update-rc $(DESTDIR)/usr/sbin install -m 755 service $(DESTDIR)/usr/sbin diff --git a/SRC/initscripts/init-functions b/SRC/initscripts/init-functions old mode 100644 new mode 100755 index c4f3150..68ccaa4 --- a/SRC/initscripts/init-functions +++ b/SRC/initscripts/init-functions @@ -13,6 +13,7 @@ if [ -r /proc/1/environ ]; then fi [ -n "$chkcontainer" ] && export $chkcontainer +[ -z "$NAME" ] && NAME=${0##*/} COL52="\\033[52G" @@ -31,13 +32,13 @@ killproc() { ;; *) pathname="$1" - signal="$2" + [ -n "$2" ] && signal="$2" break ;; esac done - [ -r "$pidfile" ] && pids=$(pidofproc -p "$pidfile" "$pathname") + [ -r "$pidfile" ] && pids=$(pidofproc -p "$pidfile" "$pathname") || return 0 [ -z "$pids" ] && pids=$(pidofproc "$pathname") [ -z "$pids" ] && [ -n "$signal" ] && return 1 [ -z "$pids" ] && return 0 @@ -67,6 +68,18 @@ log_init_msg() { echo -n "$1" } +log_begin_msg() { + log_init_msg "$1" +} + +log_end_msg() { + if [ "$1" = "0" ]; then + log_success_msg + else + log_failure_msg + fi +} + log_failure_msg() { echo "$COL52[ FAIL ]" @@ -104,7 +117,11 @@ pidofproc() { esac done - [ -r "$pidfile" ] && pids=$(head -1 $pidfile) || pids=$(pidof $pathname) + if [ -r "$pidfile" ]; then + pids=$(head -1 $pidfile|sed 's/ \+//g') + else + pids=$(pidof "$pathname") + fi for pid in $pids; do kill -0 "$pid" 2>/dev/null && pidlist="$pidlist $pid " @@ -154,3 +171,31 @@ start_daemon() { nice -n "$nicelevel" "$pathname" } +status_of_proc() { + local name pidfile pathname pids pidlist + + while true; do + case "$1" in + -p) + pidfile="$2" + shift 2 + ;; + *) + pathname="$1" + break + ;; + esac + done + + if [ -n "$pidfile" ]; then + pid=$(pidofproc -p "$pidfile" "$pathname"); + else + pid=$(pidofproc "$pathname") + fi + + if [ "$?" -ne 0 ]; then + echo "$NAME is not runing" && return 1 + else + echo "$NAME running with PID: $pid" + fi + } diff --git a/SRC/initscripts/init.d/checkfs b/SRC/initscripts/init.d/checkfs index 562848f..4145376 100755 --- a/SRC/initscripts/init.d/checkfs +++ b/SRC/initscripts/init.d/checkfs @@ -1,7 +1,7 @@ #!/bin/sh ### BEGIN INIT INFO # Provides: checkfs -# Required-Start: udev swap $time hostname +# Required-Start: checkroot hostname swap $time udev # Required-Stop: # Should-Start: # Should-Stop: @@ -13,38 +13,21 @@ . /lib/lsb/init-functions [ -z $container ] || exit 0 -[ -z "$VERBOSE" ] && VERBOSE=no -[ -z "$FSCKFIX" ] && FSCKFIX=no case "$1" in start) if [ -f /fastboot ] || grep -qwi 'fastboot' /proc/cmdline; then - log_init_msg "Fastboot enabled - skipping file system checks" + log_init_msg "Fastboot enabled - skipping fsck" log_success_msg exit 0 fi - log_init_msg "Mounting root file system in read-only mode" - mount -n -o remount,ro / >/dev/null - - if [ $? != 0 ]; then - log_failure_msg - echo - echo "Failed to mount root filesystem in read-only mode." - echo - echo "Press Enter to halt" - read - /etc/init.d/halt stop - else - log_success_msg - fi - if [ -f /forcefsck ] || grep -qwi 'forcefsck' /proc/cmdline; then - checking='Checking file systems with force' + log_init_msg "Checking file systems with force" force='-f' else - checking='Checking file systems' + log_init_msg 'Checking file systems' fi case "$FSCKFIX" in @@ -52,44 +35,31 @@ case "$1" in fix='-y' ;; *) - fix='-a' + fix='-p' ;; esac case "$VERBOSE" in 1|y|yes) echo - echo "$checking" - fsck $force $fix -A -C -T + fsck $force $fix -A -C -T -R ;; *) - log_init_msg "$checking" - fsck $force $fix -A -T >/dev/null + fsck $force $fix -A -T -R >/dev/null ;; esac status=$? - case "$VERBOSE" in - 1|y|yes) - echo - if [ "$status" = 0 ]; then - exit 0 - else - log_init_msg "Filesystem issues detected" - fi - ;; - esac - - if [ "$status" = 0 ]; then + if [ $status = 0 ]; then log_success_msg - elif [ "$status" = 1 ]; then + elif [ $status = 1 ]; then log_warning_msg echo echo "WARNING: File system errors were detected and repaired." echo - elif [ "$status" = 2 -o "$status" = 3 ]; then + elif [ $status = 2 -o $status = 3 ]; then log_warning_msg echo @@ -97,9 +67,9 @@ case "$1" in echo "The repairs require the system to be rebooted." echo echo "Press enter to reboot" - read + read reboot reboot -f - elif [ "$status" -gt 3 -a "$status" -lt 16 ]; then + elif [ $status -gt 3 -a $status -lt 16 ]; then log_failure_msg echo @@ -107,7 +77,7 @@ case "$1" in echo "repaired automatically." echo echo "Press enter to halt" - read + read halt /etc/init.d/halt stop else log_failure_msg @@ -115,7 +85,9 @@ case "$1" in echo echo "fsck exited with unexpected status: $status" echo - exit $status + echo "Press enter to halt" + read halt + /etc/init.d/halt stop fi ;; *) diff --git a/SRC/initscripts/init.d/checkroot b/SRC/initscripts/init.d/checkroot new file mode 100755 index 0000000..519c389 --- /dev/null +++ b/SRC/initscripts/init.d/checkroot @@ -0,0 +1,136 @@ +#!/bin/sh +### BEGIN INIT INFO +# Provides: checkroot +# Required-Start: hostname mountvirtfs +# Required-Stop: +# Should-Start: +# Should-Stop: +# Default-Start: S +# Default-Stop: +# Short-Description: Check root filesystem for errors +# X-Required: true +### END INIT INFO + +. /lib/lsb/init-functions +[ -z $container ] || exit 0 + +case "$1" in + start) + if [ -f /fastboot ] || grep -qwi 'fastboot' /proc/cmdline; then + log_init_msg "Fastboot enabled - skipping root fsck" + log_success_msg + + exit 0 + fi + + if [ -f /forcefsck ] || grep -qwi 'forcefsck' /proc/cmdline; then + log_init_msg "Checking root file system with force" + force='-f' + else + log_init_msg "Checking root file system" + fi + + rootdev="/dev/$(lsblk -l -o NAME,MOUNTPOINT|grep '\/$'|sed 's/ .*//')" + mount -n -o remount,ro $rootdev / >/dev/null + + if [ $? != 0 ]; then + log_failure_msg + echo + echo "Failed to mount root filesystem read-only." + echo + echo "Press Enter to halt" + read + /etc/init.d/halt stop + fi + + case "$FSCKFIX" in + 1|y|yes) + fix='-y' + ;; + *) + fix='-p' + ;; + esac + + case "$VERBOSE" in + 1|y|yes) + echo + fsck $force $fix -C -T $rootdev + ;; + *) + fsck $force $fix -T $rootdev >/dev/null + ;; + esac + + status=$? + + if [ $status = 0 ]; then + mount -n -o remount,rw $rootdev / >/dev/null + + if [ $? != 0 ]; then + log_failure_msg + echo + echo "Failed to mount root filesystem read-write." + echo + echo "Press Enter to halt" + read + /etc/init.d/halt stop + else + log_success_msg + fi + elif [ $status = 1 ]; then + mount -n -o remount,rw $rootdev / >/dev/null + + if [ $? != 0 ]; then + log_failure_msg + echo + echo "Failed to mount root filesystem read-write." + echo + echo "Press Enter to halt" + read + /etc/init.d/halt stop + else + log_warning_msg + fi + + echo + echo "WARNING: Root file system errors were detected and repaired." + echo + elif [ $status = 2 -o $status = 3 ]; then + log_warning_msg + + echo + echo "WARNING: Root file system errors were detected and repaired." + echo "The repairs require the system to be rebooted." + echo + echo "Press enter to reboot" + read reboot + reboot -f + elif [ $status -gt 3 -a $status -lt 16 ]; then + log_failure_msg + + echo + echo "Root file system errors were detected, but could not be" + echo "repaired automatically." + echo + echo "Press enter to halt" + read halt + /etc/init.d/halt stop + else + log_failure_msg + + echo + echo "fsck exited with unexpected status: $status" + echo + echo "Press enter to halt" + read halt + /etc/init.d/halt stop + fi + ;; + *) + echo "Usage: $0 [start]" + exit 1 + ;; +esac + +exit 0 diff --git a/SRC/initscripts/init.d/cleanfs b/SRC/initscripts/init.d/cleanfs index a00fde7..4f1951b 100755 --- a/SRC/initscripts/init.d/cleanfs +++ b/SRC/initscripts/init.d/cleanfs @@ -24,6 +24,16 @@ clean() { case "$1" in start) + if [ -f /fastboot ]; then + log_init_msg "Clearing /fastboot" + rm /fastboot && log_success_msg || log_failure_msg + fi + + if [ -f /forcefsck ]; then + log_init_msg "Clearing /forcefsck" + rm /forcefsck && log_success_msg || log_failure_msg + fi + log_init_msg "Cleaning temporary files" for dir in $CLEANDIRS; do diff --git a/SRC/initscripts/init.d/hwclock b/SRC/initscripts/init.d/hwclock index 624f2b2..4ae7c83 100755 --- a/SRC/initscripts/init.d/hwclock +++ b/SRC/initscripts/init.d/hwclock @@ -1,12 +1,13 @@ #!/bin/sh ### BEGIN INIT INFO # Provides: hwclock -# Required-Start: $local_fs -# Required-Stop: +# Required-Start: mountvirtfs +# Required-Stop: $local_fs # Should-Start: modules # Should-Stop: $syslog # Default-Start: S # Default-Stop: 0 6 +# X-Start-Before: checkroot # Short-Description: Synchronize the system and hardware clocks # Description: During boot sync the hardware clock to the # system clock if udev is not running. During diff --git a/SRC/initscripts/init.d/mountfs b/SRC/initscripts/init.d/mountfs index a130056..19a825e 100755 --- a/SRC/initscripts/init.d/mountfs +++ b/SRC/initscripts/init.d/mountfs @@ -1,7 +1,7 @@ #!/bin/sh ### BEGIN INIT INFO # Provides: $local_fs -# Required-Start: udev checkfs +# Required-Start: udev checkfs checkroot # Should-Start: # Required-Stop: swap # Should-Stop: @@ -9,9 +9,9 @@ # Default-Stop: 0 6 # Short-Description: Mounts/unmounts local filesystems # Description: Remounts root filesystem read/write and mounts all -# remaining local filesystems defined in /etc/fstab. -# Remounts root filesystem read-only and unmounts -# remaining filesystems on stop. +# remaining local filesystems defined in /etc/fstab +# During stop remounts root filesystem read-only and +# unmounts remaining filesystems. # X-Required: true ### END INIT INFO @@ -21,24 +21,11 @@ case "$1" in start) - log_init_msg "Remounting root file system in read-write mode" - mount -o remount,rw / >/dev/null && log_success_msg || log_failure_msg - - if [ -f /fastboot ]; then - log_init_msg "Clearing /fastboot" - rm /fastboot && log_success_msg || log_failure_msg - fi - - if [ -f /forcefsck ]; then - log_init_msg "Clearing /forcefsk" - rm /forcefsck && log_success_msg || log_failure_msg - fi - - log_init_msg "Mounting remaining file systems" + log_init_msg "Mounting local file systems" mount -a -O no_netdev >/dev/null && log_success_msg || log_failure_msg ;; stop) - log_init_msg "Unmounting all file systems" + log_init_msg "Unmounting local file systems" umount -a -d -r -t notmpfs,nosysfs,nodevtmpfs,noproc,nodevpts \ >/dev/null && log_success_msg || log_failure_msg diff --git a/SRC/initscripts/init.d/mountnetfs b/SRC/initscripts/init.d/mountnetfs new file mode 100755 index 0000000..93b677d --- /dev/null +++ b/SRC/initscripts/init.d/mountnetfs @@ -0,0 +1,34 @@ +#!/bin/sh +### BEGIN INIT INFO +# Provides: $remote_fs +# Required-Start: $local_fs $network $portmap +# Should-Start: +# Required-Stop: +# Should-Stop: +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: Mounts remote filesystems +# Description: Mounts only those filesystems labelled _netdev in +# /etc/fstab. umountfs should handle the unmounting +# X-Required: true +### END INIT INFO + +. /lib/lsb/init-functions + +[ -z $container ] || exit 0 + +case "$1" in + start) + log_init_msg "Mounting remote file systems" + mount -a -O _netdev >/dev/null && log_success_msg || log_failure_msg + ;; + stop) + # No-op + ;; + *) + echo "Usage: $0 [start|stop]" + exit 1 + ;; +esac + +exit 0 diff --git a/SRC/initscripts/init.d/mountvirtfs b/SRC/initscripts/init.d/mountvirtfs index dab6773..f57b072 100755 --- a/SRC/initscripts/init.d/mountvirtfs +++ b/SRC/initscripts/init.d/mountvirtfs @@ -3,7 +3,7 @@ # Provides: mountvirtfs # Required-Start: # Required-Stop: -# Should-Start: +# Should-Start: udev # Should-Stop: # Default-Start: S # Default-Stop: diff --git a/SRC/initscripts/init.d/reboot b/SRC/initscripts/init.d/reboot index 5780a54..1dd1d37 100755 --- a/SRC/initscripts/init.d/reboot +++ b/SRC/initscripts/init.d/reboot @@ -15,7 +15,7 @@ case "$1" in stop) - log_init_msg "Restarting system" + echo "Restarting system" reboot -d -f -i ;; diff --git a/SRC/initscripts/init.d/sendsignals b/SRC/initscripts/init.d/sendsignals index c7fb754..194816e 100755 --- a/SRC/initscripts/init.d/sendsignals +++ b/SRC/initscripts/init.d/sendsignals @@ -29,7 +29,7 @@ case "$1" in log_init_msg "Sending all processes the KILL signal" killall5 -9 - if [ "$?" = 0 -o "$?" = 2 ]; then + if [ "$?" == 0 -o "$?" == 2 ]; then success=1 fi fi diff --git a/SRC/initscripts/init.d/swap b/SRC/initscripts/init.d/swap index 698c26c..728d004 100755 --- a/SRC/initscripts/init.d/swap +++ b/SRC/initscripts/init.d/swap @@ -2,7 +2,7 @@ ### BEGIN INIT INFO # Provides: swap # Required-Start: udev -# Required-Stop: +# Required-Stop: mountfs # Should-Start: modules # Should-Stop: # Default-Start: S diff --git a/SRC/initscripts/init.d/sysctl b/SRC/initscripts/init.d/sysctl index a8aab26..4049107 100755 --- a/SRC/initscripts/init.d/sysctl +++ b/SRC/initscripts/init.d/sysctl @@ -23,7 +23,7 @@ case "$1" in sysctl -q -p && log_success_msg || log_failed_msg ;; status) - grep -v '^#' $CONF | while IFS= read -r line; do + grep -v '^#\|^$' $CONF | while IFS= read -r line; do param=`echo -n $line|sed 's/\s\+=.*//'` realval=`sysctl $param|sed 's/.*=\s\+//'` diff --git a/SRC/initscripts/service b/SRC/initscripts/service new file mode 100755 index 0000000..8093c40 --- /dev/null +++ b/SRC/initscripts/service @@ -0,0 +1,11 @@ +#!/bin/sh + +# A simple wrapper for /etc/init.d scripts + +SERVICEDIR="/etc/init.d" +SERVICE=${1} + +[ -x "${SERVICEDIR}/${SERVICE}" ] && exec "${SERVICEDIR}/${SERVICE}" $2 + +echo "${SERVICE}: unrecognized service" +exit 1 diff --git a/SRC/initscripts/update-rc b/SRC/initscripts/update-rc index 142fdd1..98ac15c 100755 --- a/SRC/initscripts/update-rc +++ b/SRC/initscripts/update-rc @@ -5,10 +5,22 @@ use strict; use Data::Dumper; +use constant COMMANDS => qw( disable enable required status ); use constant INITDIR => '/etc/init.d'; use constant RUNLEVELS => qw( S 1 2 3 4 5 6 0 ); -use constant SVCKEYS => qw( Provides Required-Start Required-Stop Should-Start - Should-Stop Default-Start Default-Stop Short-Description Description ); +use constant SVCKEYS => qw( + Provides + Required-Start + Required-Stop + Should-Start + Should-Stop + X-Start-Before + X-Start-After + Default-Start + Default-Stop + Short-Description + Description + ); use constant VERBOSE => eval { for ( my $i = 0; $i <= $#ARGV; $i++ ) { if ( $ARGV[$i] eq '-v' || $ARGV[$i] eq '--verbose' ) { @@ -21,25 +33,56 @@ use constant VERBOSE => eval { return( 0 ); }; -sub chkstatus { - my $svcname = shift; - my $status = {}; +sub enable { + my $service = shift || error( -1, "enable(): service not provided" ); + my $services = shift || error( -1, "enable(): services not provided" ); - foreach my $rlvl ( RUNLEVELS ) { - my $dir = "/etc/rc$rlvl.d"; - - opendir( DIR, $dir ); - - while ( readdir( DIR ) ) { - if ( $_ =~ /^([KS])(\d+)$svcname$/ ) { - $status->{$rlvl} = $1; - } - } - - close( DIR ); + if ( $service->{'enabled'} ) { + return; } - return( $status ); + if ( VERBOSE ) { + print "Enabling $service->{'name'}\n"; + } + + foreach my $rlvl ( @{$service->{'Default-Stop'}} ) { + $service->{'rlvls'}{$rlvl} = 'K'; + } + foreach my $rlvl ( @{$service->{'Default-Start'}} ) { + $service->{'rlvls'}{$rlvl} = 'S'; + } + + $service->{'enabled'} = 1; + + if ( ! $service->{'Required-Start'} ) { + return; + } + + foreach my $svc ( keys( %{$services} ) ) { + if ( grep( $_ eq $svc, @{$service->{'Required-Start'}} ) && + ! $services->{$svc}{'enabled'} ) { + if ( VERBOSE ) { + print " $service->{'name'} requires $svc\n"; + } + + enable( $services->{$svc}, $services ); + } + elsif ( ref( $services->{$svc}{'Provides'} ) eq 'ARRAY' && + ! $services->{$svc}{'enabled'} ) { + foreach my $provides ( + @{$services->{$svc}{'Provides'}} ) { + if ( grep( $_ eq $provides, + @{$service->{'Required-Start'}} ) ) { + if ( VERBOSE ) { + print " $service->{'name'}" + . " requires $svc\n"; + } + + enable( $services->{$svc}, $services ); + } + } + } + } } sub error { @@ -47,12 +90,13 @@ sub error { my $errstr = shift; my $level = 1; my @stack = (); + ( my $self = ( caller() )[1] ) =~ s/.*\///; chomp( $errstr ); print "\n"; - print STDERR ( caller() )[1] .":\n $errstr at line " + print STDERR "$self:\n $errstr at line " . ( caller() )[2] . "\n"; if ( VERBOSE ) { @@ -73,104 +117,157 @@ sub error { } } -sub kdepends { - my $services = shift; - my $service = shift; - my $kdepends = shift || []; +sub getsvcrlvls { + my $service = shift || + error( -1, "getsvcrlvls(): service not provided\n" ); + + foreach my $rlvl ( RUNLEVELS ) { + my $dir = "/etc/rc$rlvl.d"; + + opendir( my $dh, $dir ) || + error( int( $! ), "getsvcrlvls(): opendir(): $!" ); + + while ( readdir( $dh ) ) { + if ( ! -l "$dir/$_" ) { + next; + } + + my $link = readlink( "$dir/$_" ) || + error( int( $! ), + "getsvcrlvls(): readlink(): $!" ); + ( my $name = $link ) =~ s/.*\///; + + if ( $name eq $service->{'name'} && + $_ =~ /^([KS])(\d+)$service->{'name'}$/ ) { + $service->{'rlvls'}{$rlvl} = $1; + } + } + + closedir( $dh ); + } + } + +sub korder { + my $service = shift || error( -1, "korder(): service missing" ); + my $services = shift || error( -1, "korder(): services missing" ); + my $korder = shift || []; my $stack = shift || []; - if ( @$stack > 99 ) { + if ( ( $stack->[0] && grep( $_ eq $service, @$stack ) ) || + ( $korder->[0] && grep( $_->{'name'} eq $service, @$korder ) ) || + @$stack > 99 ) { return; } + else { + push( @$stack, $service ); + } - push( @$stack, $service->{'name'} ); + foreach my $svc ( sort( keys( %{$services} ) ) ) { + if ( $service eq 'halt' || $service eq 'reboot' ) { + korder( $svc, $services, $korder, $stack ); - foreach my $svcname ( sort( keys( %{$services} ) ) ) { - my $provides = $services->{$svcname}{'Provides'}; - - if ( $stack->[0] && grep( $_ eq $svcname, @$stack ) ) { next; } - foreach my $required ( @{$service->{'Required-Stop'}} ) { - if ( grep( $_ eq $required, @$provides ) ) { - kdepends( $services, $services->{$svcname}, - $kdepends, $stack ); - - if ( ! grep( $_ eq $svcname, @$kdepends ) ) { - unshift( @$kdepends, $svcname ); - } - } + if ( ( $services->{$svc}{'X-Stop-After'} && grep( $_ eq + $service, @{$services->{$svc}{'X-Stop-After'}} ) ) || + ( $services->{$svc}{'Required-Stop'} && grep( $_ eq $service, + @{$services->{$svc}{'Required-Stop'}} ) ) || + ( $services->{$svc}{'Should-Stop'} && grep( $_ eq $service, + @{$services->{$svc}{'Should-Stop'}} ) ) ) { + korder( $svc, $services, $korder, $stack ); } - foreach my $required ( @{$service->{'Should-Stop'}} ) { - if ( grep( $_ eq $required, @$provides ) ) { - kdepends( $services, $services->{$svcname}, - $kdepends ); - if ( ! grep( $_ eq $svcname, @$kdepends ) ) { - unshift( @$kdepends, $svcname ); + if ( $services->{$service}{'Provides'} ) { + foreach my $provides ( + @{$services->{$service}{'Provides'}} ) { + if ( ( $services->{$svc}{'Required-Stop'} && + grep( $_ eq $provides, + @{$services->{$svc}{'Required-Stop'}} ) ) || + ( $services->{$svc}{'Should-Stop'} && + grep( $_ eq $provides, + @{$services->{$svc}{'Should-Stop'}} ) ) ) { + korder( $svc, $services, $korder, + $stack ); } } } } - return( $kdepends ); + push( @$korder, $services->{$service} ); } -sub readinfo { +sub readlsb { my $file = shift; my $begin = 0; my $prev; - my $service = { + my $lsb = { 'Provides' => [], 'Required-Start' => [], 'Required-Stop' => [], 'Should-Start' => [], 'Should-Stop' => [], + 'X-Start-Before' => [], + 'X-Stop-After' => [], 'Default-Start' => [], 'Default-Stop' => [], 'Short-Description' => '', 'Description' => '' }; + my @splitpath = split( '/', $file ); + my $override; + my @files; - open( FILE, "<$file" ) || error( int( $! ), "open(): $file: $!" ); + $splitpath[-1] = '.' . $splitpath[-1]; + $override = join( '/', @splitpath ); - while ( ) { - chomp(); + push( @files, $file ); - if ( substr( $_, 0, 19 ) eq '### BEGIN INIT INFO' ) { - $begin++; - - next; - } - elsif ( substr( $_, 0, 17 ) eq '### END INIT INFO' ) { - last; - } - elsif ( ! $begin ) { - next; - } - - if ( $_ =~ /^#\s*((Short\-|)Description):\s*(.*)/ ) { - $service->{$1} = $3; - $prev = $1; - } - elsif ( $_ =~ /^#\s*(\S+):\s*(.*)/ ) { - $service->{$1} = []; - $prev = $1; - - push( @{$service->{$1}}, split( /\s+/, $2 ) ); - } - elsif ( $prev && $prev =~ /Description/ && $_ =~ /^#\s*(.*)/ ) { - $service->{$prev} .= " $1"; - } - elsif ( $prev && $_ =~ /^#\s*(.*)/ ) { - push( @{$service->{$prev}}, split( /\s+/, $1 ) ); - } + if ( -f $override ) { + push( @files, $override ); } - close( FILE ); + foreach ( @files ) { + open( FILE, "<$_" ) || error( int( $! ), "open(): $_: $!" ); - return( $service ); + while ( ) { + chomp(); + + if ( substr( $_, 0, 19 ) eq '### BEGIN INIT INFO' ) { + $begin++; + + next; + } + elsif ( substr( $_, 0, 17 ) eq '### END INIT INFO' ) { + last; + } + elsif ( ! $begin ) { + next; + } + + if ( $_ =~ /^#\s*((Short\-|)Description):\s*(.*)/ ) { + $lsb->{$1} = $3; + $prev = $1; + } + elsif ( $_ =~ /^#\s*(\S+):\s*(.*)/ ) { + $lsb->{$1} = []; + $prev = $1; + + push( @{$lsb->{$1}}, split( /\s+/, $2 ) ); + } + elsif ( $prev && $prev =~ /Description/ && + $_ =~ /^#\s*(.*)/ ) { + $lsb->{$prev} .= " $1"; + } + elsif ( $prev && $_ =~ /^#\s*(.*)/ ) { + push( @{$lsb->{$prev}}, split( /\s+/, $1 ) ); + } + } + + close( FILE ); + } + + return( $lsb ); } sub readsvcs { @@ -185,7 +282,7 @@ sub readsvcs { next; } - $services->{$svcname} = readinfo( INITDIR . "/$svcname" ); + $services->{$svcname} = readlsb( INITDIR . "/$svcname" ); if ( ! @{$services->{$svcname}{'Provides'}} ) { delete( $services->{$svcname} ); @@ -194,7 +291,7 @@ sub readsvcs { } $services->{$svcname}{'name'} = $svcname; - $services->{$svcname}{'status'} = chkstatus( $svcname ); + getsvcrlvls( $services->{$svcname} ); } close( DIR ); @@ -202,156 +299,228 @@ sub readsvcs { return( $services ); } -sub sdepends { - my $services = shift; - my $service = shift; - my $sdepends = shift || []; +sub sorder { + my $service = shift || error( -1, "sorder(): service missing" ); + my $services = shift || error( -1, "sorder(): services missing" ); + my $sorder = shift || []; my $stack = shift || []; - if ( $stack->[0] && grep( $_ eq $service->{'name'}, @$stack ) - || @$stack > 99 ) { + if ( ! keys( %{$services->{$service}{'rlvls'}} ) ) { return; } - - push( @$stack, $service->{'name'} ); - - foreach my $svcname ( sort( keys( %{$services} ) ) ) { - my $provides = $services->{$svcname}{'Provides'}; - - if ( $stack->[0] && grep( $_ eq $svcname, @$stack ) ) { - next; + elsif ( ( $stack->[0] && grep( $_ eq $service, @$stack ) ) || + ( $sorder->[0] && grep( $_->{'name'} eq $service, @$sorder ) ) || + @$stack > 99 ) { + return; + } + else { + if ( VERBOSE ) { + print "Checking start order for $service\n"; } - foreach my $required ( @{$service->{'Required-Start'}} ) { - if ( grep( $_ eq $required, @$provides ) ) { - sdepends( $services, $services->{$svcname}, - $sdepends, $stack ); + push( @$stack, $service ); + } - if ( ! grep( $_ eq $svcname, @$sdepends ) ) { - push( @$sdepends, $svcname ); - } + if ( ! @$sorder ) { + push( @$sorder, $services->{'hostname'} ); + } + + foreach my $svc ( sort( keys( %{$services} ) ) ) { + if ( $services->{$svc}{'X-Start-Before'} && grep( + $_ eq $service, @{$services->{$svc}{'X-Start-Before'}} ) ) { + if ( VERBOSE ) { + print " $svc should be before $service\n"; } - } - foreach my $required ( @{$service->{'Should-Start'}} ) { - if ( grep( $_ eq $required, @$provides ) ) { - sdepends( $services, $services->{$svcname}, - $sdepends, $stack ); - if ( ! grep( $_ eq $svcname, @$sdepends ) ) { - push( @$sdepends, $svcname ); + sorder( $svc, $services, $sorder, $stack ); + } + } + + if ( ref( $services->{$service}{'Required-Start'} ) eq 'ARRAY' ) { + MAINLOOP: foreach my $required ( + @{$services->{$service}{'Required-Start'}} ) { + if ( $services->{$required} && ! grep( + $_->{'name'} eq $required, @$sorder ) ) { + if ( VERBOSE ) { + print " $service requires service" + . " $required\n"; + } + + sorder( $services->{$required}{'name'}, + $services, $sorder, $stack ); + + next; + } + + foreach my $svc ( sort( keys( %{$services} ) ) ) { + if ( ref( $services->{$svc}{'Provides'} ) + eq 'ARRAY' && grep( $_ eq $required, + @{$services->{$svc}{'Provides'}} ) && ! grep( + $_->{'name'} eq $svc, @$sorder ) ) { + if ( VERBOSE ) { + print " $service requires" + . " service $svc\n"; + } + + sorder( $svc, $services, + $sorder, $stack ); + + next MAINLOOP; } } } } - return( $sdepends ); + if ( ref( $services->{$service}{'Should-Start'} ) eq 'ARRAY' ) { + MAINLOOP: foreach my $should ( + @{$services->{$service}{'Should-Start'}} ) { + if ( $services->{$should} ) { + if ( VERBOSE ) { + print " $service should start" + . " $should first\n"; + } + + sorder( $services->{$should}{'name'}, + $services, $sorder, $stack ); + + next; + } + + foreach my $svc ( sort( keys( %{$services} ) ) ) { + if ( ref( $services->{$svc}{'Provides'} ) + eq 'ARRAY' && grep( $_ eq $should, + @{$services->{$svc}{'Provides'}} ) ) { + if ( VERBOSE ) { + print " $service requires" + . " service $svc\n"; + } + + sorder( $svc, $services, + $sorder, $stack ); + + next MAINLOOP; + } + } + } + } + + push( @$sorder, $services->{$service} ); + pop( @$stack ); + + if ( VERBOSE ) { + print "Service $service added to start order\n"; + } } -my $command = shift( @ARGV ); +my $command = shift( @ARGV ) || error( -1, "No command supplied" ); my $services = readsvcs(); -my $kserv = []; -my $sserv = []; +my $ksvcs = []; +my $ssvcs = []; -if ( $command !~ /disable|enable|required/ ) { +if ( ! grep( $_ eq $command, &COMMANDS ) ) { error( -1, "$command: invalid command" ); } -if ( $command eq 'disable' ) { +if ( $command eq 'enable' || $command eq 'disable' ) { foreach ( @ARGV ) { - if ( $services->{$_}{'X-Required'} ) { - print STDERR "Not disabling required service '$_'\n"; + if ( $command eq 'enable' ) { + enable( $services->{$_}, $services ); + } + elsif ( $command eq 'disable' ) { + if ( $services->{$_}{'X-Required'} && + $command eq 'disable' ) { + print STDERR "Not disabling required" + . " service '$_'\n"; + next; + } + + foreach my $rlvl ( keys( + %{$services->{$_}{'rlvls'}} ) ) { + delete( $services->{$_}{'rlvls'}{$rlvl} ); + } + } + } + } + +foreach my $svc ( sort( keys( %$services ) ) ) { + korder( $svc, $services, $ksvcs ); + sorder( $svc, $services, $ssvcs ); + + if ( $services->{$svc}{'X-Required'} && + ! $services->{$svc}{'enabled'}) { + enable( $services->{$svc}, $services ); + } + } + +foreach my $rlvl ( &RUNLEVELS ) { + my $rcdir = "/etc/rc$rlvl.d"; + my $kcnt = 0; + my $scnt = 0; + + if ( VERBOSE ) { + print "\n[RUNLEVEL $rlvl]\n"; + } + + opendir( my $rc, $rcdir ) || error( int( $! ), + "opendir(): $rcdir: $!" ); + + while ( readdir( $rc ) ) { + if ( -l "$rcdir/$_" ) { + my $target = readlink( "$rcdir/$_" ) || error( + int( $! ), "readlink(): $rcdir/$_: $!" ); + ( my $service = $target ) =~ s/.*\///; + + if ( $services->{$service} ) { + unlink( "$rcdir/$_" ) || error( int( $! ), + "unlink(): $rcdir/$_: $!" ); + } + } + } + + closedir( $rc ); + + for ( my $i = 0; $i <= $#$ksvcs; $i++ ) { + if ( ! $ksvcs->[$i]{'rlvls'}{$rlvl} ) { next; } - undef( $services->{$_} ); - } - } + if( grep( $_ eq $rlvl, @{$ksvcs->[$i]{'Default-Stop'}} ) ) { + my $script = "../init.d/$ksvcs->[$i]{'name'}"; + my $link = sprintf( "%s/%s%02d%s", $rcdir, + $ksvcs->[$i]{'rlvls'}{$rlvl}, + $kcnt, $ksvcs->[$i]{'name'} ); -foreach my $svcname ( sort( keys( %$services ) ) ) { - if ( keys( %{$services->{$svcname}{'status'}} ) || - $services->{$svcname}{'X-Required'} ) { - push( @ARGV, $svcname ); - } - } - -foreach my $svcname ( sort( @ARGV ) ) { - my $service = $services->{$svcname}; - - if ( ! $service ) { - error( -1, "$svcname: invalid service name" ); - } - - sdepends( $services, $services->{$svcname}, $sserv ); - - if ( ! grep( $_ eq $svcname, @$sserv ) ) { - push( @$sserv, $svcname ); - } - - kdepends( $services, $services->{$svcname}, $kserv ); - - if ( ! grep( $_ eq $svcname, @$kserv ) ) { - if ( $svcname !~ /halt|reboot/ ) { - unshift( @$kserv, $svcname ); - } - else { - push( @$kserv, $svcname ); - } - } - } - -foreach my $rlvl ( RUNLEVELS ) { - my $dir = "/etc/rc$rlvl.d"; - my $startcnt = 0; - my $stopcnt = 0; - my $cnt = 0; - - if ( VERBOSE ) { - print "[Runlevel $rlvl]\n"; - } - - opendir( DIR, $dir ) || - error( int( $! ), "opendir(): $dir: $!" ); - - foreach ( sort( readdir( DIR ) ) ) { - if ( $_ =~ /^(K|S)\d{2}/ ) { - unlink( "$dir/$_" ) || - error( int( $! ), "unlink(): $dir/$_: $!" ); - } - } - - close( DIR ); - - foreach my $kdepend ( @$kserv ) { - if ( grep( $_ eq $rlvl, - @{$services->{$kdepend}{'Default-Stop'}} ) ) { - my $link = sprintf( "K%02d%s", $stopcnt, $kdepend ); - symlink( "../init.d/$kdepend", "$dir/$link" ) || - error( int( $! ), "symlink(): $dir/$link: $!" ); + symlink( $script, $link ) || error( int( $! ), + "symlink(): $link: $!" ); if ( VERBOSE ) { - print "$dir/$link -> ../init.d/$kdepend\n"; + print "$link\n"; } - $stopcnt++; + $kcnt++; } } - foreach my $sdepend ( @$sserv ) { - if ( grep( $_ eq $rlvl, - @{$services->{$sdepend}{'Default-Start'}} ) ) { - my $link = sprintf( "S%02d%s", $startcnt, $sdepend ); - symlink( "../init.d/$sdepend", "$dir/$link" ) || - error( int( $! ), "symlink(): $dir/$link: $!" ); + + for ( my $i = 0; $i <= $#$ssvcs; $i++ ) { + if ( ! $ssvcs->[$i]{'rlvls'}{$rlvl} ) { + next; + } + + if ( grep( $_ eq $rlvl, @{$ssvcs->[$i]{'Default-Start'}} ) ) { + my $script = "../init.d/$ssvcs->[$i]{'name'}"; + my $link = sprintf( "%s/%s%02d%s", $rcdir, + $ssvcs->[$i]{'rlvls'}{$rlvl}, + $scnt, $ssvcs->[$i]{'name'} ); + + symlink( $script, $link ) || error( int( $! ), + "symlink(): $link: $!" ); if ( VERBOSE ) { - print "$dir/$link -> ../init.d/$sdepend\n"; + print "$link\n"; } - $startcnt++; + $scnt++; } } - - if ( VERBOSE ) { - print "\n"; - } }