[NLUUG]   Welcome to ftp.nluug.nl
Current directory: /pub/ibiblio/distributions/amigolinux/download/AmigoProjects/sysvinit-dash/
 
Current bandwidth utilization 423.26 Mbit/s
Bandwidth utilization bar
Contents of README:
	Gilbert Ashley <amigo@ibiblio.org> 19 October 2010 

	On creating (mostly?) POSIX-compliant init scripts for Slackware,
	including the use of ash or dash as the shell to run them.

	These are notes to myself, but may be useful to anyone else
	considering the implementation of an alternative shell for
	use with Slackware init scripts.
	
	The goal of this project is *not* to replace /bin/sh with /bin/dash.
	Doing that would make me/us responsible for many obscure, hard-to-find
	breakages which are simply unwanted -including failure of configure
	scripts (especially from old sources) and failure of sundry scripts
	grabbed from who-knows-where.
	
The init scripts in these sources are comprised of a combination of
ideas and code from Sasha Alexander(sic?), Tom Goya and Gilbert
Ashley. They are based on the standard Slackware init scripts from
Slackware-12.1/12.2 (IIRC).

In order to update them to include any changes made in the standard
scripts since 12.1/12.2, create a diff of the official 12.1 and
whatver later version you are comparing to. Then, review each of the
patch 'hunks' to see if they need be applied. 

***
POSIX-compliant != ash != dash != sh(bash as sh):
The meaning of 'POSIX-compliant' is undefined here. Assuming full
(and 'pure') POSIX-compliance (with whichever POSIX version), is
probably not the best goal to have for this project. Offering a
viable alternative to using bash in the least intrusive manner
should serve better and perhaps be more likely to get consideration
from PatV for upstreaming any work into official Slackware (something
that I highly doubt, BTW). 

Still, if one pretends to offer installable packgages or scripts to 
build them to others, a seamless way to upgrade and downgrade should be
provided.

dash is advertized as being POSIX-compliant, but may support one or
two features which are not compliant(echo -n, $(commands) instead 
of `commands`). It has been awhile now since 12.1/12.2 were current 
and we three worked on this, so my recollection of specific differences
has waned a bit...
For our purposes, the main difference between Slackware's 'ash' and 'dash'
is that dash supports $(), whereas ash does not. Check again about 
(echo -n ..) when using either. One would also need to check compatibility 
when sourcing sub-scripts which need the 'start' parameter passed to them.


***
Comparsion of three approaches (and content) from Sasha, Tim and Gilbert:

1. Like Tim, I dislike the two-space indentation used in most of the
original scripts, so diffing between his or my scripts against the
standard ones (or between each other) will show up lots of 'white-space-only' 
changes which can certainly be ignored. (Tim likes using three-space
indentation and I like four-space.)

2. Tim adopted another change which is mostly about style: that of
using exclusively explicit 'test' statements, instead of the standard
tests which use single brackets. If looking at diffs of Tim's scripts
against the standard ones (or mine), most of the individual patch hunks
that occur have to do with these 'test'-vs-'[]' syntax changes. Although
many of the scripts I include are based on those by Tim, I did not use
this alternative 'test' syntax.

3. Tim included several core-funtionality changes which can be adopted
or not.
	a. rc.4 has a changed routine for checking and using a given
	   display manager.
	b. rc.6 contains some 'echo -n' usage which may not be
	   'POSIX-compliant'. Using explicit calls to /bin/echo
	   eliminates the problem (there aren't many of these, but good
	   to review for them.
	c. rc.M loops through a list of 'services' to optionally run minor 
	   sub-scripts which are called individually in the standard scripts.
	   (I like this approach, but wound up leaving it out for the
	   time-being as being one-strutural-change-too-many. It does look
	   nicer, it's easier to modify the order of execution and add
	   services, and should be very slightly faster.)
	   
4. Sasha's scripts included many extra rc.* files which are not part of
the regular sysvinit or init-scripts packages from Slackware. They also
include some customizations which are probably specific to her system. I also found
a probable typo/bug in Sasha's rc.inet1 (missing closing ' or " around 110-117 IIRC)

5. Tim's modified scripts comprise the least number of files.

At first, I only modified the basic scripts (rc.S, rc.M, etc) along with some
of the most basic 'optional' ones which promised to make the most difference in 
lowering bootup times, like rc.udev. I also tackled a few older or more complex 
ones which were not so likely to be used, but are specifically called by the main
scripts and offered considerable chance for faster run-times, like rc.serial
and rc.scanluns(the real changes are in rescan-scsi-bus.sh)

I later started modifying many of the standard scripts, but because of packaging
and maintenance considerations, I scaled down the scope of the endeavour to
only encompass the main scripts included in the standard package and the important ones
which offered most benefit and/or were called directly by the main scripts. Anything
started after messagebus and hald in rc.M should be non-critical and can be handled
by un-modified scripts, if properly called by our main scripts.

6. There is some syntax inconsistency and variation in the standard scripts which
makes things a little confusing at times -especially regarding the sourcing
of subscripts with and without the 'start' parameter. Some scripts adapted from
debian or redhat-style systems, and other very old standard ones have differences
in syntax vis-a-vis 'case $action in' vs. 'case $1 in'. Another thing to be careful
of is sub-scripts which contain any 'exit' statements -sourcing them in any manner
will cause early abortion of the init scripts. Sasha (later) came up with a method using
function calls to enable sourcing sub-scripts with parameters. However, doing this
implies assuring that any such sub-scripts be syntax-compliant with whatever shell
we are hoping to use for the init scripts. 

I had used a syntax like this:
action=start /etc/rc.d/rc.subscript 
which relied on modifying each sub-script to support the use of the $action variable. 
Many standard scripts use 'start' as the default parameter if none is given, but not 
all of them. My scripts still contain lines like:
action=${action:-$1}
even though I found a possibly better solution. First, executing the scripts like this:
/etc/rc.d/rc.subscript start
makes them work okay. But, that is bad if any routines fail or contain an 'exit'. So,
I wound up explicitly calling them using 'sh /etc/rc.d/rc.subscript start'. But, since
some of these sub-scripts are ones that are altered to use our chosen 'init shell', calling
them with 'sh' wastes several cycles/time is lost resoving the path to 'sh' which then 
loads a script which may have '#!/bin/our-favourite-init-shell' as the shebang, which
wastes more time starting our-favourite-init-shell to run the code.

Some sub-scripts which are called without any parameters may be using the default 'action'
as explained above. But, most of them are scripts which indeed need no paramters. Most
rc.program scripts which are supplied by the individual package are like this.

My solution to this wound up being the use of an explicit shebang for our chosen init
shell which is used for any sub-scripts which are modified to use ash/dash and are
included with the distributed scripts package. Any other subscripts which need a separate
shell, or that formerly were sourced with a supplied parameter, are instead explicitly
called like this:
sh /etc/rc.d/rc.subscript start
or:
sh /etc/rc.d/rc.subscript
sub-scripts which are modified for ash/dash are called like this:
/bin/our-favourite-init-shell /etc/rc.d/rc.subscript start

7. Because of compatibility and upgrade/downgrade considerations, I settled on using
scripts which are run by the shell named /bin/initsh. This allows us to be flexible
and use dash, ash or bash as the shell for our init processes, without having to
replace bash-as/bin/sh as the main system 'sh' -doing so would never happen in Slackware
and would cause loads of grief like what debian/mandriva had when they change to
using 'dash' as their /bin/sh. I wanted to be able to create a package which could
be installed and used with dash(if installed), ash(if installed) or bash (as standard).
So the doinst.sh script and naming-convention of the files in my packages are adjusted
to this functionality. My main sysvinit package was also slightly changed to fit with
this idea. For the fastest execution of the init scripts, one should copy or rename
the chosen shell as /bin/initsh. Having /bin/initsh as a link to ash or dash will slow
down things somewhat as resoving links takes time(just as the standard scheme having
/bin/sh as a link to /bin/bash).

8. My scripts also contain a few hunks of changes which are non-standard. My rc.udev
includes some code which allows for use with both older and newer versions of udev, which
can be ignored(udevcontrol reload_rules vs udevadm control --reload-rules).

9. I found some compat issues in wildcard path expansion in rc.udev (grep for 'for TMPFILE in')
and (maybe?)in rc.S at '# Clean up some temporary files:' (check use of constructs like:
'*/*/*' and 'kde-[a-zA-Z]*'

10. Both Tim and Sasha did extensive re-writes of one or main scripts -each with their
own ideas/methods. One in particular is rc.inet1. I wound up using Tim's as the base
for mine, although I now don't remember exactly why I chose his.

11. The doinst.sh and sysvinit-scripts.src2pkg scripts included in my sources provide
(among other things), a review or prioritization of many of the most important sub-scripts
which are mostly supplied as part of their own package. In order to avoid any need to
maintain a bunch of accessory scripts, I tried to come up with a way of calling all
extra scripts in a generic way which would be compatible with whatever shebang and
syntax they normally use. Their use is completely optional on most any system, so
any possible bootup time savings from modifying them would have a minimal effect on
boot time. Hence, it is easy and feasible to leave them out of the main init-scripts
package.

12. Though my changes are structurally more extensive, they are/were still a Work In Progress.
Using my scripts, I was able to achieve a boot-up time of 7-8 seconds on a 2.0 GHz
Pentium IV machine, compared with a timf of around 30 seconds on the same machine
using the standard scripts. Some of this (huge) time-saving is accounted for by
commenting a 3-second sleep(waiting for USB drivers in rc.S) and by backgrounding the
processes in rc.M of this type: *update-*
The total savings of those is around 5-7 seconds, so YMMV regarding actual time-savings
on your system. My system was also booting with very few optional services activated.

13. My packages still include some sub-scripts which should not be included in the main
init-scripts package. Since I built packages for my own system, some of the content
may be mixed as compared to current Slackware packges. I wavered between building packages
like old-style Slackware packages where init scripts were included with sysvinit, instead
of being in separate package(s).

Notes on speed optimizations:
A. Running in-line code is faster than calling a function which includes the code
B. Calling a link is slower than calling the prgram directly.
C. Calling a program without the absolute path is slower than calling it with
 full path as the system must resolve the real location from possible paths.
D. Startup latency of dash or ash is negligible as compared to bash, so explicitly
 using separate instances of ash/dash is nearly as fast as sourcing a bash
  sub-script fragment or executing a script with /bin/sh shebang. I'm referring
  here to the tradeoffs between using:
. /etc/rc.d/some.script start
/etc/rc.d/some.script start
/bin/initsh /etc/rc.d/some.script start
 The conevntion I used was to use the last alternative only for scripts which are
 specifically modified for ash/dash. Other cases should probably use:
/bin/sh /etc/rc.d/some.script start
for best results with unknown syntax or syntax in files you don't want to include
in your mods. Occasionally, individuals will create or modify init scripts from
other systems which contain an 'exit'. Directly executing the scripts with a separate
instance of /bin/sh will avoid premature aborting of init routines if the scripts
contain any 'exit' statements.
E. Some of the scripts at the core of the *early* init process offer the best
opportunity for speed optimization. rc.inet1 and rc.udev come to mind. Both have
*lots* of 'if', 'else' checks which can be quite slow.
F. Using 'case' statements is faster than using 'if', '[]' or 'test'
G. Using shell features to replace some string-manipulation calls to sed and awk, 
will prove faster in every case (in these short init scripts), although the syntax
may be less clear to most 'reviewers'.
H. Using a modified installation of dash, where the main binary is named /bin/initsh
will produce slightly faster times than having /bin/initsh as a link to /bin/dash.

My efforts were not aimed at achieving the fastest bootup *at any cost*. Rather,
I tried to create package content/structure/concepts which would provide good
speed-ups while maintaining flexibility for use by others and adhere to Slackware
'just-works' and upgrade/downgrade concepts. The doinst.sh uses an 'abundance of
caution' approach by creating backups of original bash-syntaxed files, so a user
might recover a borked conversion to /bin/initsh scripts with a 'brute force' of
renaming backed-up files to the original names. And I considered the various scenarios
of using my scripts with no dash or ash present, or with either one of the two already
present when installing my packages.

***
At the time I was working on these scripts, I was also investigating general syntax
differences between Slackware's ash, busybox's ash, (various) BSD ash versions, dash,
bash 2.?, bash-3.? and others. There is no shell which is 100% POSIX-compliant and
does not include any other features. dash does appear to be the closets thing, but
includes a couple of extra features. Many people, when talking about POSIX-compliance,
may actually mean compliance with traditional 'sh' or traditional 'Bourne shell'.
Traditional sh is probably best represented by the 'sh' from the heirloom project
( on sourceforge). And traditional Bourne shell is probably best represented by the
shell called 'jsh', when called as 'sh' or anything other than 'jsh'. Calling the
shell as 'jsh' turns on job-control features, whereas calling it as 'sh' or 'bsh'
will run it without job-control. Any effort to create very-cross-compatible shell
code can be enhanced by testing the code against both jsh and the 'heirloom' sh.
Both of them are very similar to the original Solaris 'sh' syntax which is still
a viable criteria for many people.

busybox ash is not equal to any other version of ash -but its' syntax and features
should be considered for any scripts which might be included in an installer initrd
or any system which might (foolishly?) try to use busybox ash as the main shell
or as the shell used for init scripts. Other busybox shells like 'lash' are nowhere
near similar or comaptible with anything else...

The Slackware version of 'ash' is not the same as anyone else's. It is getting harder
to get it to compile and at least one Slacker has reported it seg-faulting on
Slackware64 when hitting 'backspace' more than once -I'm not sure if his 'fix' for
the problem has been incorporated into the official packages.

checkbashisms.pl helps find some obscure, hard-to-spot cases of 'iffy' code. If I
had any perl 'fu' at all, I'd add a few lines and options to it to recognize a few
of the differences mentioned below...

***
Review of some questionable syntax to watch out for:
a. Use of [-e FILE ] is not POSIX-compliant(I forget right now if dash/ash accept this. Use
[-r FILE ] or [-x FILE ] instead.

b. wildcard path expansion is 'flaky' with ash/dash. Using 'ls' with wildcards will usually work, but
is not really a good idea either, for other reasons.

c. ash doesn't support $() -use `` instead. dash does support $() 

d. sourcing files with a following parameter doesn't work with ash or dash

e. watch out for 'echo -n' It's not used often in the scripts -changing to use
/bin/echo should be an adequate fix. One might test using printf, but make sure
both ash and dash give the desired results...

f. watch out for comments appended to the end of code lines -ash and dash may
accept them, but the syntax is not POSIX-compliant(IIRC). Mainly, I mention this
because I find comments after code onerous to read.

g. watch out for comparisons of unquoted variables. This works:
[ 'some-value' != $UNQUOTED_VARIABLE ]
where this does not:
[ $UNQUOTED_VARIABLE != 'some-value' ]
Still, I find the first example counter-intuitive to read. Using this:
[ "QUOTED_VARIABLE" != 'some-value' ]
should also always work.

h. Slackware's init scripts have slowly become more and more bash-dependent, using
 arrays and expansions/substitutions which are not compatible with other shells.
 Tim and Sashas mods have addressed the worst cases of this. checkbashisms will
 identify these bad spots, but in particular, converting code to not use arrays
 is no easy matter.

i. Using bash-style double brackets '[[]]' cures and hides some hard-to-spot and
 hard-to-fix cases where single brackets '[]' or 'test' might need to be used -maybe
 especially in common constructs which are using grep within brackets. Conversions
 to single brackets should be carefully tested. Tim submitted some code to me for
 use in src2pkg which used simple 'test' instead of any brackets and I never did
 find the way to make the test successful with any brackets at all. It still bothers
 me because it's the only code in src2pkg which does use simple 'test' instead of brackets.

j. Be careful with any code using 'sed'. Older versions of 'standard' sed or busybox
 versions of sed will surely have differences when compared with modern sed.

k. I found a spot where 'awk' is used in the init scripts. I eliminated it as I thought
that requiring sed during boot-up to be 'over the top'. Follow your own heart...

Have fun re-booting your machine with the install CD to temporarily be 'in business'
again after experimenting with these scripts. :=) Or, use a VM or qemu to ease things
abit. *DO NOT* blindly install packages built from my scripts without backing up your
original /etc/rc.d directory! Some of my concepts may not have been fully implemented
at the time I stopped working on these scripts. Still, using packages created using my
src2pkg build scripts and the included doinst.sh scripts will be much better than simply
copying these scripts into /etc/rc.d to replaces the standard ones. Especially because
of the renaming and shebang conventions I have adopted, these scripts will simply leave
your system unbootbale unless my doinst.sh is used.

Icon  Name                                                          Last modified      Size  
[DIR] Parent Directory - [DIR] rc.d-sasha/ 20-Oct-2010 22:15 - [DIR] rc.d-tim/ 20-Oct-2010 22:14 - [DIR] sysvinit-scripts-dash-1.0/ 20-Oct-2010 22:13 - [DIR] sysvinit-scripts-dash-1.1/ 20-Oct-2010 22:14 - [DIR] sysvinit-scripts-dash-1.2/ 20-Oct-2010 22:14 - [DIR] sysvinit-scripts-dash-1.3/ 20-Oct-2010 22:13 - [TXT] README 20-Oct-2010 23:10 19K

NLUUG - Open Systems. Open Standards
Become a member and get discounts on conferences and more, see the NLUUG website!