// COMBAK: openrc, whole page
= Working with OpenRC

OpenRC is the init system used in alpine.
The init system manages the services, startup and shutdown of your computer.

[NOTE]
====
In this section, the canonical names of utilities are used.
For instance, `rc-service` instead of `service`.
For many of these, the traditional name (e.g `service`) is also available, but that is not the case for all of them.
If in doubt, use the canonical name, as is shown in this document.
====

== Normal Usage
=== Manipulating Services
// COMBAK: openrc, whole page
==== Runtime Service Manipulation
You manipulate services on a running system using the `rc-service` command.
This allows you to start, stop, and check the status of a given service, amongst other things.
See the following basic examples:

[source,sh]
----
rc-service networking stop <1>
rc-service sshd start <2>
rc-service chronyd status <3>
----
<1> Stop the networking service.
<2> Start the sshd service.
<3> See the status of the chronyd service.

`rc-service` also supports a few flags, which are primarily useful for scripting.
// TODO: link rc-service(8)
You can see the full list in the `rc-service(8)` manual page.
Of particular interest are the following:

-c | --ifcrashed::
Only run the specified command if the service has crashed.
-N | --ifnotstarted::
Only run the specified command if the service is not currently started.
-s | --ifstarted::
Only run the specified command if the service is currently started.

NOTE: Services may define additional commands you can use. See more on this in <<_custom_service_commands>>.

// COMBAK: rc-update
==== On-Boot Service Manipulation
OpenRC operates under a system called "runlevels".
More on that in <<_switching_runlevels>> and <<_custom_runlevels>>.
Enabling a service means putting it in a runlevel, usually one that will get loaded automatically (but not necessarily so!).
Disabling a service involves removing it from one or more runlevels.
This is all done using the `rc-update` utility, which updates various runlevels.
It may be used as such:

[source,sh]
----
rc-update show -v <1>
rc-update add sshd default <2>
rc-update add sshd <3>
rc-update delete sshd <4>
rc-update delete chronyd -a <5>
----
<1> View the current services in any runlevel. The `-v` flag will also show various services that are not in any runlevel.
<2> Add the sshd service to the default runlevel.
<3> If you do not specify a runlevel, your current one will be used. This is equivalent to the 2nd example under normal operation.
<4> Remove the sshd service from the current runlevel, as with add.
<5> Remove the chronyd service from all runlevels.

=== Configuring Services
Various services may need additional configuration.
Most will have dedicated configuration files in `/etc` - you can see documentation on the specific service for more details.
However, some services need configuration applied to them as part of the launch procedure - such as passing a flag to the binary when first started.
This can be done in the `/etc/conf.d` directory, under the name of the service in question.
For example, for a service named "base", the configuration file would be `/etc/conf.d/base`.

// COMBAK: rc-status
=== System Status
The `rc-status` utility is a fast way to view the current state of your system's services.
By default, it will list all the services in the current runlevel.
You can select a different runlevel by specifying it, for instance, `rc-status boot` will list all the services in the boot runlevel.
It also accepts various flags that change what it does.
// TODO: link rc-status(8)
As per usual, the full list is available in the `rc-status(8)` manual page.
Here are the more interesting ones:

-c | --crashed::
Show a list of all the crashed services.
-l | --list::
List all the available runlevels.
-s | --servicelist::
Show a list of all the services.

== Advanced Usage

=== Custom Runlevels

==== Creating

Most users will be happy with just the default runlevel.
Other users will want more.
A runlevel is simply a directory in `/etc/runlevels`, and an enabled service is a symlink to the `init.d` file.
For example, adding the `sshd` service to the `default` runlevel is creating a symlink to `/etc/init.d/sshd` in `/etc/runlevels/default`.
Creating a new runlevel thus involves creating a new directory under `/etc/runlevels`.

==== Runlevel Stacking
Most of the time, you do not want to shut down all of your `default` services if you're switching to the `office` runlevel.
Runlevel "inheritance" is acheived through runlevel stacking.
If you pass the `-s` flag to `rc-update`, you can actually add a runlevel to a runlevel.
For example, if you wanted to have an `office` runlevel that would be the same as `default`, but with the `myvpn` service started, you would do the following to set that up:

[source,sh]
----
mkdir /etc/runlevels/office
rc-update -s add default office
rc-update add myvpn office
----

==== Switching Runlevels
Once you have a custom runlevel you want to switch to, you can do so using the `openrc` command.
As per the above example, you would use `openrc office` to switch to your new runlevel, and `openrc default` to switch back.

// TODO: expand
=== System Configuration
System-wide configuration of OpenRC happens in `/etc/rc.conf`.

=== Multi-Services
In some cases, you may want the same bit of code to do different things under different circumstances.
For example, normally, the difference between various instances of `agetty` are just the tty they run on.
In these cases, you can use symlinks to manage dynamic configuration differences.

Consider `agetty` - it determines what port (tty) to run on by calculating `${RC_SVCNAME#*.}`.
This means that if your service name is `agetty.foo`, the port variable will have "foo" as its value.
The intended way to use this is by symlinking the "base" service (`agetty`) to the desired target (`agetty.foo`).

This mechanism also allows you to specify custom configuration for that service, for more details, see <<_extended_conf_d_names>>.

=== Custom Service Commands
Commands other than `start`, `stop` and `status` may be available.
A common example is `save`, used by `iptables`.
Their usage is identical to that of the built-in ones.
You can look inside the `init.d` script at various `extra*commands` variables which give a listing of the available ones.
// TODO: what's extra_started_commands etc?

// COMBAK: the insanity in sh/opnenrc-init.sh.in
=== Extended `conf.d` Names
There are 4 total files that may play a role in the configuration of a service.
Assume that `base` stands for the name of the base server, `ext` is the extension (as per <<_multi_services>>) and `runlevel` is the runlevel it's in.
Under those conditions, the files involved are:

`/etc/conf.d/base.runlevel`::
OpenRC will try loading this file if the full name of the service is not the same as the base name of the service.
`/etc/conf.d/base`::
If OpenRC tried loading `/etc/conf.d/base.runlevel` and failed, it will try loading this file.
`/etc/conf.d/base.ext.runlevel`::
OpenRC will always try loading this file, but only after the above two have happened.
`/etc/conf.d/base.ext`::
If loading `/etc/conf.d/base.ext.runlevel` failed, OpenRC will try to load this file.

As far as most people are concerned, OpenRC will first load `/etc/conf.d/base` and then overlay `/etc/conf.d/base.ext` on top of it.
