FreeBSD init ============ The FreeBSD init system is rc.d, which was adopted from NetBSD. rc.d is based on the traditional BSD init (incorporates some ideas from SystemV init). rc.d has these improvements over the old init system: - Dependency ordering is easier than manually shifting around chunks of the old `/etc/rc/` script. - Sysadmins can start, stop, and restart services with a single command, rather than killing processes by PID and starting them by cobbling together snippets from `/etc/rc` and `/etc/rc.conf`. - It's easier to sysadmins (and package management scripts) to add local service startups. - It provides a mechanism for the orderly shut down of services. ## Background: 4.4BSD init ## At boot, `/sbib/init` runs as the first process. It spawns `/bin/sh` to run `/etc/rc`. The `/etc/rc` script checks and mounts filesystems, starts daemons, runs `/etc/netstart`, and finally starts any local services from `/etc/rc.local`. After `/etc/rc` completes, init forks a copy of itself for each tty. At shutdown, init simply sends SIGHUP to each process, waits ten seconds for the processes to clean themselves up, sends SIGNTERM and waits ten seconds, and finally sends SIGKILL to each remaining process. ## SystemV init ## SVR4 init.d, like that used by Solaris, is built around the concept of run levels. `/sbin/init` runs at boot, and launches `/sbin/init`. `/sbin/init` runs `/etc/inittab`, which points to directories of scripts for each run level. For example, `/etc/rc1.d/` starts everything for single-user mode, `/etc/rc3.d/` has scripts for all the nulti-user stuff including NFS, and `/etc/rc5.d` contains all the shutdown scripts. These scripts are normally symlinks to scripts in `/etc/init.d/`. Because services are started with individual scripts, it's easy for an administrator to restart a service like `/etc/init.d/foo restart`. Services can be enabled or disabled by adding or removing the script from the `/etc/rcN.d/` directory. Some init.d systems have `/etc/rcN.d/Sfoo` and `/etc/rcN.d/Kfoo` scripts to start and stop services each time run level N is entered or exited. ## rc.d ## On boot, init runs `/etc/rc`. `/etc/rc` asks `rcorder` to order and resolve dependencies for any scripts in `/etc/rc.d/` (except for scripts marked 'nostart'). `/etc/rc` runs each script returned by `rcorder` with a 'start' argument. File | Purpose ---------------------:|:--------------------------------- /etc/rc | System start-up /etc/rc.shutdown | System shutdown script /etc/rc.d/* | Individual service start-up scripts /etc/rc.subr | Common shell code reused by rc scripts /etc/defaults/rc.conf | Default options /etc/rc.conf | System options /etc/rc.conf.d/* | Per-service configs `/etc/rc.conf` allows administrators to easily specity which services should be started and their basic flags, like: foo_enable="YES" foo_option="bar" The settings in `/etc/rc.conf` override the defaults in `/etc/defaults/rc.conf`. `/etc/rc.shutdown` gets runs before init sends SIGHUP to everything. This allows ordered shutdown of certain services (e.g. stop a front-end service before shutting down its back-end database). The shutdown order is resolved by `rcorder`, but in the opposite order as start-up. Administrators can control services easily by calling individual scripts like `/etc/rc.d/foo restart`. To see the order in which services will be started: % rcorder /etc/rc.d/* /usr/local/etc/rc.d/* Scripts in `/etc/rc.d/` all support 'start' and 'stop' arguments. Some also support 'restart', 'status', and 'rcvar' (which shows any `/etc/rc.conf` variables that can be set for it). % /usr/local/etc/rc.d/sshguard status sshguard is running as pid 624. % /usr/local/etc/rc.d/sshguard rcvar # sshguard # sshguard_enable="YES" # (default: "") The 'onestart' argument can be used to manually activate a service that is not enabled at boot by `/etc/rc.conf`: % /etc/rc.d/foo onestart ('onestart' is safer than 'forcestart'. 'forcestart' skips prerequisite checks and ignores errors.) ## Writing An rc.d Script ## See the examples in `/etc/rc.d/` and rc(8). Scripts must be written for `/bin/sh`. Place the script in `/usr/local/etc/rc.d/`. Remember to make the script executable. A commented example: #!/bin/sh # These directives are parsed by `rcorder`. # The PROVIDE line names how other scripts can REQUIRE this service: # PROVIDE: foo # Run this service after those REQUIREd. ALLUPPERCASE placeholders are described in rc(8). BEFORE also exists, but should be used with caution. # REQUIRE: NETWORKING bar # Keywords include: # - 'nojail': don't run in jail environments # - 'nostart': don't start or only start manually # - 'shutdown': run service shutdown function before init starts generally sending SIGHUP to everything # KEYWORD: shutdown # Include common rc.d functions: . /etc/rc.subr # Note that some network-related function are in `/etc/network.subr`. # 'name' is mandatory: name='foo' # Set name of on/off knob for `/etc/rc.conf`: rcvar=foo_enable command="/usr/local/bin/foo" # Argument added after $foo_flags (don't include flags here): command_args="my arguments > /dev/null 2>&1" pidfile="/var/run/${name}.pid" # Require files to exist before daemon runs. # required_dirs and required_vars (environmental variables) also can be defined. # forcestart skips these requirements. required_files="/usr/local/etc/foo.conf" # Load the rc.conf variables: load_rc_config $name # run_rc_command will complain if rcvar is set and the knob value is not set: : ${foo_enable:=no} : ${foo_msg="Not started."} start_cmd="${name}_start" # Override stop with no-op, since we are just echoing and exiting: stop_cmd=":" foo_start() { echo "$foo_msg" } # Usually the last command of an rc.d script: run_rc_cmd "$1" ## Further Reading ## - init(8) - rc(8) - rcorder(8) - rc.subr(8) - sh(1) - http://www.mewburn.net/luke/papers/rc.d.pdf <--- This is really good. - https://www.freebsd.org/doc/en/articles/linux-users/startup.html - https://www.freebsd.org/doc/en_US.ISO8859-1/articles/rc-scripting/index.html