Subject: PROPOSAL: /etc/rc, /etc/init.d/*, ...
To: None <tech-userlevel@netbsd.org>
From: Luke Mewburn <lukem@cs.rmit.edu.au>
List: tech-userlevel
Date: 12/01/1999 12:48:50
Introduction
============

This document describes a proposal for an implementation of
/etc/init.d/* scripts for NetBSD. It is based on work and ideas
by Luke Mewburn, Matthew Green, and others.

It has been felt by many people that NetBSD needs a more flexible
method of system startup scripts. Exactly what model is used to
improve flexibility is a contentious issue, but we feel that this
proposal has the benefits of many other systems without the warts,
whilst retaining backward compatibility for those that require it.

The current methodology of startup scripts that NetBSD uses is a
variant on the `traditional' BSD ``/etc/rc'': a single monolithic
script with behaviour controlled by variables set in /etc/rc.conf.
Some other scripts are called (netstart, rc.lkm, rc.local, rc.wscons),
but you get the general idea.

A `traditional' SYSV ``/etc/init.d/'' directory has been suggested,
but there a various `warts' in that system that can be rectified
in a new design.


Scope
=====

A new system should have the following attributes:
	* Separate scripts for each function, which support
	  `start' and `stop' type functionality.
	* Ordering with more control than numeric prefixes on
	  scripts (c.f. rcorder(8)).
	* Control over a function via /etc/rc.conf (rather than
	  via the existance of a file/link in /etc/rc*.d).
	* The ability to generate /etc/rc and /etc/rc.shutdown
	  from `/etc/init.d/*'.
	* Implementers should be able to add extra actions to a
	  script (e.g, `reload', `debugon', etc) fairly easily.
	* Optional checks that a process isn't running before
	  starting, is running before stopping, etc...


The solution
============

a) Extra functions in /etc/rc.subr

	check_pidfile pidfile procname
		Parses the first line of pidfile for a process id,
		and checks that the pid matches procname.
		Prints the pid.

	check_process procname
		Ensures that a process (or processes) named procname
		is running. Prints a list of matching pids.

	run_rc_command arg [supported_args]
		Scan supported_args (which has "start stop restart status"
		prepended) for arg. If there's a match, run ${arg}_cmd
		or the default command.

   run_rc_command is the `meat' of the system. You set a few variables
   and call it and things `just work'.

b) /etc/init.d/

	This contains files - one for each function to execute on
	startup - which can either be invoked directly or used to
	generate /etc/rc (via mkrc).

	Currently there are 75 scripts in /etc/init.d.

	NOTE:	During development this directory was called `/etc/rc.d'.
		It was changed to `/etc/init.d' because:
		    a) prior art (cf. SYSV), and people are used to running
			/etc/init.d/foo start
		    b) `completion-conflict-with-rc[03].d' asthetics :-)

		If there's a strong argument for /etc/rc.d over
		/etc/init.d, we could rename it to /etc/rc.d.

c) /etc/rc.sh

	A script which effectively does:
		for i in `rcorder /etc/init.d/*`; do
			$i faststart
		done
	(`faststart' is like start but without the check for
	running processes).

	If a user wants to use this method (instead of having to
	rebuild /etc/rc when necessary), just symlink /etc/rc.sh
	to /etc/rc.

d) /etc/rc.shutdown.sh

	Similar to /etc/rc.sh, but reverses the order of the output
	of `rcorder /etc/init.d/*`, and calls each script with `stop'.

e) /etc/rc.sysv.sh

	A script which effectively does:
		for i in /etc/rc3./S*; do
			$i start
		done

	This is provided for users who like the `Sxx' and `Kxx' style
	names.

f) /sbin/mkrc

	Depending upon the options, mkrc generates /etc/rc, /etc/rc.shutdown,
	/etc/rc0.d and /etc/rc3.d from /etc/init.d/*.

	The generated /etc/rc{,.shutdown} is rather readable sh script
	(especially for machine generated scripts!)

	/etc/rc0.d will contain symlinks from KxxFOO -> ../init.d/FOO.
	/etc/rc3.d will contain symlinks from SxxFOO -> ../init.d/FOO.

g) /etc/netstart

	A wrapper for /etc/init.d/network and /etc/init.d/ppp


An example script - /etc/init.d/mountd - is as follows (indented for
readability):

    ====
	# PROVIDE: mountd
	# REQUIRE: beforemountlkm network portmap

	. /etc/rc.subr

	name="mountd"
	rcvar="nfs_server"
	command="/usr/sbin/${name}"
	required_files="/etc/exports"

	start_precmd=\
	'rm -f /var/db/mountdtab
	echo -n > /var/db/mountdtab
	:'

	run_rc_command "$1" "reload"
    ====

This is one of the more complicated startup scripts. It uses a
different rc.conf variable than the daemon name, it depends upon
/etc/exports, a `pre command' operation is run before the actual
daemon if all the startup conditions are met. `reload' is added
to the list of commands which are supported; this defaults to
sending a SIGHUP but that can be changed with sig_reload=SIGfoo.

A simpler one - /etc/init.d/rwho - is:

    ====
	# PROVIDE: rwho
	# REQUIRE: daemon

	. /etc/rc.subr

	name="rwhod"
	command="/usr/sbin/${name}"

	run_rc_command "$1"
    ====

The functionality provided by this proposed system should cater
for the majority of needs.


Availability
============

A tar file containing a snapshot of the work in progress is available from:
	ftp://ftp.netbsd.org/pub/NetBSD/misc/lukem/rc-19991201.tar.gz


Implementation timeframe
========================

Once I've tested this stuff a bit more, parts of this start appearing
in the standard distribution. The existing /etc/rc scripts won't be
modified (except for /etc/netstart; but the functionality should
remain).

After that, /etc/rc could be replaced by the output of /sbin/mkrc. 


Feedback
========

Thoughts/comments?