7 Commits

Author SHA1 Message Date
Jay Larson
0ac62b6e9a Updated status_of_proc to properly deal with stopped process that uses pidfile 2018-10-07 16:11:58 -05:00
Jay Larson
795ed0feaa Updated init-functions to be more thorough in checking pids 2018-10-05 16:54:46 -05:00
Jay Larson
c6456ba7d3 Modified init-functions so that pidofproc properly returns non-zero 2018-09-30 19:07:50 -05:00
Jay Larson
a101cfe1c0 Added dependencies on grep and sed 2018-09-30 18:43:44 -05:00
Jay Larson
843c8721f1 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
2018-07-28 14:30:08 -05:00
Jay Larson
7de71fa1cd The following changes were made:
* Add URL
  * Removed /etc/rcX.d directories (should be provided by sysvinit)
  * Added 'service' script
  * Properly set VERBOSE and FSCKFIX in init.d/checkfs
  * Used = in favor of == in checkfs, halt and sendsignals
  * Removed ZFS from mountfs
2018-04-10 11:25:20 -05:00
Jay Larson
97906ebe04 init-functions now checks for read access before attempting to read environ 2017-12-10 11:47:48 -06:00
21 changed files with 688 additions and 325 deletions

View File

@@ -8,9 +8,9 @@
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
DEPENDS = dash,kmod,procps-ng,sysvinit
DEPENDS = dash,grep,kmod,perl,procps-ng,sed,sysvinit
ARCH = x86_64
URL =
URL = http://snaplinux.org
REPO = core
BRIEF = Base scripts for sysvinit
DESC = This package supplies the core required init scripts for startup
@@ -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.5-0
VERSION := 1.12-0
include /usr/share/snap/Makefile.snaplinux
@@ -35,5 +35,6 @@ clean:
@rm -rvf $(ROOT) \
$(SNAPINFO) \
$(MANIFEST) \
$(FILES)
$(FILES) \
$(CONFIG)

View File

@@ -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

View File

@@ -1,34 +1,19 @@
dirs:
install -d -m 755 $(DESTDIR)/etc/default
install -d -m 755 $(DESTDIR)/etc/{rc{{0..6},S},init}.d
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
install: dirs files

91
SRC/initscripts/init-functions Normal file → Executable file
View File

@@ -8,8 +8,12 @@
# be enough
#
if [ -r /proc/1/environ ]; then
chkcontainer=$(sed 's/\x0/\n/g' < /proc/1/environ|grep -ia '^container\|^LXC')
fi
[ -n "$chkcontainer" ] && export $chkcontainer
[ -z "$NAME" ] && NAME=${0##*/}
COL52="\\033[52G"
@@ -28,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
@@ -64,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 ]"
@@ -101,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 "
@@ -151,3 +171,68 @@ 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
# Here we use LSB as a reference for the return values:
#
# 0 program is running or service is OK
# 1 program is dead and /var/run pid file exists
# 2 program is dead and /var/lock lock file exists
# 3 program is not running
# 4 program or service status is unknown
# 5-99 reserved for future LSB use
# 100-149 reserved for distribution use
# 150-199 reserved for application use
# 200-254 reserved
#
# As you can see however, for now we just support 0, 1, 3 and 4
# May do something for 2 at some point, but the other status
# codes should not be used here - they're only here for reference
if [ -n "$pidfile" ]; then
if [ -r "$pidfile" ]; then
pid=$(pidofproc -p "$pidfile" "$pathname")
if [ "$?" -eq 0 ]; then
echo "$NAME running with PID: $pid" && return 0
else
echo "$NAME is not running" && return 1
fi
else
pid=$(pidofproc "$pathname")
if [ "$?" -eq 0 ]; then
echo "Cannot read pid file ($pidfile)"
echo "$NAME running with PID: $pid"
return 4
else
echo "$NAME is not running"
return 3
fi
fi
else
pid=$(pidofproc "$pathname")
if [ "$?" -eq 0 ]; then
echo "$NAME running with PID: $pid"
return 0
else
echo "$NAME is not runing"
return 3
fi
fi
}

View File

@@ -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:
@@ -17,32 +17,17 @@
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
@@ -50,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
@@ -95,7 +67,7 @@ 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
log_failure_msg
@@ -105,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
@@ -113,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
;;
*)

136
SRC/initscripts/init.d/checkroot Executable file
View File

@@ -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

View File

@@ -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

View File

@@ -19,11 +19,11 @@ case "$1" in
poweroff='-p'
netdown='-i'
if [ "$HALT" == "halt" ]; then
if [ "$HALT" = "halt" ]; then
poweroff=''
fi
if [ "$NETDOWN" == "no" ]; then
if [ "$NETDOWN" = "no" ]; then
netdown=''
fi

View File

@@ -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

View File

@@ -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 or
# in ZFS. 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,41 +21,14 @@
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
if [ -x /sbin/zpool ]; then
if zpool list rpool 2>&1 > /dev/null; then
log_init_msg "Mounting ZFS file systems"
zfs mount -a && log_success_msg || log_failure_msg
fi
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
if [ -x /sbin/zpool ]; then
if zpool list rpool 2>&1 > /dev/null; then
log_init_msg "Unmounting ZFS file systems"
zfs umount -a && log_success_msg || log_failure_msg
fi
fi
mount -o remount,ro /
;;
*)

View File

@@ -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

View File

@@ -3,7 +3,7 @@
# Provides: mountvirtfs
# Required-Start:
# Required-Stop:
# Should-Start:
# Should-Start: udev
# Should-Stop:
# Default-Start: S
# Default-Stop:

View File

@@ -15,7 +15,7 @@
case "$1" in
stop)
log_init_msg "Restarting system"
echo "Restarting system"
reboot -d -f -i
;;

View File

@@ -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

View File

@@ -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\+//'`

11
SRC/initscripts/service Executable file
View File

@@ -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

View File

@@ -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;
}
if ( $service->{'enabled'} ) {
return;
}
close( DIR );
if ( VERBOSE ) {
print "Enabling $service->{'name'}\n";
}
return( $status );
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,67 +117,118 @@ sub error {
}
}
sub kdepends {
my $services = shift;
my $service = shift;
my $kdepends = shift || [];
my $stack = shift || [];
sub getsvcrlvls {
my $service = shift ||
error( -1, "getsvcrlvls(): service not provided\n" );
if ( @$stack > 99 ) {
return;
}
foreach my $rlvl ( RUNLEVELS ) {
my $dir = "/etc/rc$rlvl.d";
push( @$stack, $service->{'name'} );
opendir( my $dh, $dir ) ||
error( int( $! ), "getsvcrlvls(): opendir(): $!" );
foreach my $svcname ( sort( keys( %{$services} ) ) ) {
my $provides = $services->{$svcname}{'Provides'};
if ( $stack->[0] && grep( $_ eq $svcname, @$stack ) ) {
while ( readdir( $dh ) ) {
if ( ! -l "$dir/$_" ) {
next;
}
foreach my $required ( @{$service->{'Required-Stop'}} ) {
if ( grep( $_ eq $required, @$provides ) ) {
kdepends( $services, $services->{$svcname},
$kdepends, $stack );
my $link = readlink( "$dir/$_" ) ||
error( int( $! ),
"getsvcrlvls(): readlink(): $!" );
( my $name = $link ) =~ s/.*\///;
if ( ! grep( $_ eq $svcname, @$kdepends ) ) {
unshift( @$kdepends, $svcname );
if ( $name eq $service->{'name'} &&
$_ =~ /^([KS])(\d+)$service->{'name'}$/ ) {
$service->{'rlvls'}{$rlvl} = $1;
}
}
}
foreach my $required ( @{$service->{'Should-Stop'}} ) {
if ( grep( $_ eq $required, @$provides ) ) {
kdepends( $services, $services->{$svcname},
$kdepends );
if ( ! grep( $_ eq $svcname, @$kdepends ) ) {
unshift( @$kdepends, $svcname );
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->[0] && grep( $_ eq $service, @$stack ) ) ||
( $korder->[0] && grep( $_->{'name'} eq $service, @$korder ) ) ||
@$stack > 99 ) {
return;
}
else {
push( @$stack, $service );
}
foreach my $svc ( sort( keys( %{$services} ) ) ) {
if ( $service eq 'halt' || $service eq 'reboot' ) {
korder( $svc, $services, $korder, $stack );
next;
}
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 );
}
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 );
push( @files, $file );
if ( -f $override ) {
push( @files, $override );
}
foreach ( @files ) {
open( FILE, "<$_" ) || error( int( $! ), "open(): $_: $!" );
while ( <FILE> ) {
chomp();
@@ -151,26 +246,28 @@ sub readinfo {
}
if ( $_ =~ /^#\s*((Short\-|)Description):\s*(.*)/ ) {
$service->{$1} = $3;
$lsb->{$1} = $3;
$prev = $1;
}
elsif ( $_ =~ /^#\s*(\S+):\s*(.*)/ ) {
$service->{$1} = [];
$lsb->{$1} = [];
$prev = $1;
push( @{$service->{$1}}, split( /\s+/, $2 ) );
push( @{$lsb->{$1}}, split( /\s+/, $2 ) );
}
elsif ( $prev && $prev =~ /Description/ && $_ =~ /^#\s*(.*)/ ) {
$service->{$prev} .= " $1";
elsif ( $prev && $prev =~ /Description/ &&
$_ =~ /^#\s*(.*)/ ) {
$lsb->{$prev} .= " $1";
}
elsif ( $prev && $_ =~ /^#\s*(.*)/ ) {
push( @{$service->{$prev}}, split( /\s+/, $1 ) );
push( @{$lsb->{$prev}}, split( /\s+/, $1 ) );
}
}
close( FILE );
}
return( $service );
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;
}
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";
}
push( @$stack, $service->{'name'} );
push( @$stack, $service );
}
foreach my $svcname ( sort( keys( %{$services} ) ) ) {
my $provides = $services->{$svcname}{'Provides'};
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";
}
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 );
if ( $stack->[0] && grep( $_ eq $svcname, @$stack ) ) {
next;
}
foreach my $required ( @{$service->{'Required-Start'}} ) {
if ( grep( $_ eq $required, @$provides ) ) {
sdepends( $services, $services->{$svcname},
$sdepends, $stack );
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";
}
if ( ! grep( $_ eq $svcname, @$sdepends ) ) {
push( @$sdepends, $svcname );
}
}
}
foreach my $required ( @{$service->{'Should-Start'}} ) {
if ( grep( $_ eq $required, @$provides ) ) {
sdepends( $services, $services->{$svcname},
$sdepends, $stack );
sorder( $svc, $services,
$sorder, $stack );
if ( ! grep( $_ eq $svcname, @$sdepends ) ) {
push( @$sdepends, $svcname );
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";
}
my $command = shift( @ARGV );
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 ) || 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;
}
undef( $services->{$_} );
foreach my $rlvl ( keys(
%{$services->{$_}{'rlvls'}} ) ) {
delete( $services->{$_}{'rlvls'}{$rlvl} );
}
}
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;
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 "[Runlevel $rlvl]\n";
print "\n[RUNLEVEL $rlvl]\n";
}
opendir( DIR, $dir ) ||
error( int( $! ), "opendir(): $dir: $!" );
opendir( my $rc, $rcdir ) || error( int( $! ),
"opendir(): $rcdir: $!" );
foreach ( sort( readdir( DIR ) ) ) {
if ( $_ =~ /^(K|S)\d{2}/ ) {
unlink( "$dir/$_" ) ||
error( int( $! ), "unlink(): $dir/$_: $!" );
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/$_: $!" );
}
}
}
close( DIR );
closedir( $rc );
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: $!" );
for ( my $i = 0; $i <= $#$ksvcs; $i++ ) {
if ( ! $ksvcs->[$i]{'rlvls'}{$rlvl} ) {
next;
}
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'} );
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";
}
}