Subject: Re: /etc/rc. use bsd.rc.mk instead.
To: Julian Assange <proff@iq.org>
From: Matthew Orgass <darkstar@pgh.net>
List: tech-userlevel
Date: 12/06/1999 04:14:15
[... use make ...]

  Great idea!  If enough people would be willing to consider this, I would
be happy to put together an implementation of this.  More details below.

  First, to answer some concerns raised:
* To specify an optional source use .OPTIONAL.  This can be enhance by
adding the equivalent of -k as a special source and allowing it to be
combined with .OPTIONAL.
* Yes, you can do dependencies both ways.  You just can't directly specify
the targets in the individual files, they must be created later from
variables.
* Normally the dependency list will be kept as a file, so you only need to
regenerate it when you change something.  If you don't do so manually, it
will be done for you the next time you do something (if the next thing you
do is boot, the dependency list used in the boot process will be generated
on the fly and the file will be written once the system is up).  This
nomally gives you the speed of a generated file with the flexibility of
not needing to create it manually (though it would be a good idea to do so
to test the configuration).
* For those who want to know exactly what is going on, it is easy to print
out an exact list of what commands will be run in what order.
* SysV runlevels can be emulated (including both level change behaviors
(though obviously only one at a time :) )).
* For those who whish to do so, all config info may be kept in a single
file.  Otherwise, the individual files may be used as scripts (and *do*
check dependencies).
* It does require some somewhat heavy make magic, but nothing unmanageable
if documented properly.

  Some details of what this would look like (my version at least,
details may be altered of course):

1) /etc/init.d/* would contain makefile fragments that set variables
describing dependencies and start/stop/whatever commands.  #! magic lets
use use these files as script after boot.  You can also use them to e.g. 
stop everything that depends on this service (which, as far as I can tell,
is not possible with the current proposal.  The given URL does not seem to
be valid, so I can't look at it in more detail).

2) At boot time, make checks if a generated dependency file is up to date. 
If so, it uses it.  If not, it schedules the file to be created after the
boot (the disk is ro at this point) and builds the dependencies from the
init.d/* files. 

3) The dependencies are built in /etc/bsd.rc.mk based on the defined
variables.  This makes building stop dependencies easy (and is the only
way I can think of to do this).  This also makes the init.d/* files much
shorter.

4) Start and stop helper programs are available to spimplify common tasks
such as writing (and killing from) a pid file, watchdog functions,
detaching and redirecting IO, logging error messages once syslogd is up,
etc.  Most start and stop commands would just call this program with the
desired options, the name of the program(s) to be run, and the program's
options.  Of course the helper programs do not need to be used if the
program has start/stop scripts which do sane things.

5) A sample init.d file might look like this:
---
#!/sbin/make -sf

ITEMS+=			/sbin/myd
myd.boot=		yes
myd.depends=		something
myd.actions=		default log
myd.start.args=		-args
myd.restart.depends=	myd-stoponly .WAIT myd-startonly
myd.log=		/sbin/myd -showlog
myd.log.depends=	none

.include <bsd.rc.mk>
---

Default actions are:
start		-- start myd and dependencies
startonly	-- just start myd
startdep	-- start myd and dependents
stop		-- stop myd and dependents
stoponly	-- stop just myd
restart		-- thisitem-stop .WAIT thisitem-startdep

  The full target is name-action, however when a init.d file is called as
a script, actions default to ${ITEM:T} (as long as there is only one word
in ${ITEM}).

  The default start command is ${START} ${STARTOPTS_NOWATCH} ${ITEM}
${${ITEM:T}.start.args}.  The default stop command is ${STOP} myd, which
looks in /var/run for myd.pid and kills the process (first gently, then
with force).  It is only run after processes that depend on myd are
stopped. The default restart is myd-stop .WAIT myd-startdep, which stops
and starts all dependents as well, however this script redefines it to
just stop and start this process (which might be a more useful default). 
If desired, myd.restart.depends could be set to none and myd.restart set
to the command to run to restart myd.  myd.boot=yes says to run myd at
boot time. /etc/rc.conf is not used, though a centralized configuration
file could certainly be created if desired (and rc.conf could be made to
work if necessary).

BENEFITS:
+ -j Just Works
+ You can hack one program and speed up both builds and boot :)
+ Does not require a utility that duplicates makes functions

COSTS:
- No one else does anything like this
- You need a wrapper to run a script (but not a very complex one)
- It would be hard to make it get along with the current scheme

Matthew Orgass
darkstar@pgh.net