aboutsummaryrefslogtreecommitdiff
path: root/guide.md
blob: a3195b081aefed4c40a9a86b12e852c75d9957c9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
# Purpose and description

OpenRC is an init system for Unixoid operating systems. It takes care of 
startup and shutdown of the whole system, including services.

It evolved out of the Gentoo "Baselayout" package which was a custom pure-shell 
startup solution. (This was both hard to maintain and debug, and not very 
performant)

Most of the core parts are written in C99 for performance and flexibility 
reasons, while everything else is posix sh.
The License is 2-clause BSD

Current size is about 10k LoC C, and about 4k LoC shell.

OpenRC is known to work on Linux, many BSDs (FreeBSD, OpenBSD, DragonFlyBSD at 
least) and HURD.

Services are stateful (i.e. start; start will lead to "it's already started")

# Startup

Usually PID1 (aka. init) calls the OpenRC binary ("/sbin/openrc" by default).
(The default setup assumes sysvinit for this)

openrc scans the runlevels (default: "/etc/runlevels") and builds a dependency 
graph, then starts the needed service scripts, either serialized (default) or in 
parallel.

When all the init scripts are started openrc terminates. There is no persistent 
daemon. (Integration with tools like monit, runit or s6 can be done)

# Shutdown

On change to runlevel 0/6 or running "reboot", "halt" etc., openrc stops all 
services that are started and runs the services in the "shutdown" runlevel.

# Modifying Service Scripts

Any service can, at any time, be started/stopped/restarted by executing 
"rc-service someservice start", "rc-service someservice stop", etc.
Another, less preferred method, is to run the service script directly,
e.g. "/etc/init.d/service start", "/etc/init.d/service stop", etc.

OpenRC will take care of dependencies, e.g starting apache will start network 
first, and stopping network will stop apache first.

There is a special command "zap" that makes OpenRC 'forget' that a service is 
started; this is mostly useful to reset a crashed service to stopped state 
without invoking the (possibly broken) stop function of the service script.

Calling "openrc" without any arguments will try to reset all services so
that the current runlevel is satisfied; if you manually started apache it will be 
stopped, and if squid died but is in the current runlevel it'll be restarted.

There is a "service" helper that emulates the syntax seen on e.g. older Redhat 
and Ubuntu ("service nginx start" etc.)

# Runlevels

OpenRC has a concept of runlevels, similar to what sysvinit historically 
offered. A runlevel is basically a collection of services that needs to be 
started. Instead of random numbers they are named, and users can create their 
own if needed. This allows, for example, to have a default runlevel with 
"everything" enabled, and a "powersaving" runlevel where some services are 
disabled.

The "rc-status" helper will print all currently active runlevels and the state 
of init scripts in them:

# rc-status
 * Caching service dependencies ... [ ok ]
Runlevel: default
 modules                     [  started  ]
 lvm                         [  started  ]

All runlevels are represented as folders in /etc/runlevels/ with symlinks to 
the actual init scripts.

Calling openrc with an argument ("openrc default") will switch to that
runlevel; this will start and stop services as needed.

Managing runlevels is usually done through the "rc-update" helper, but could of 
course be done by hand if desired.
e.g. "rc-update add nginx default" - add nginx to the default runlevel
Note: This will not auto-start nginx! You'd still have to trigger "rc" or run 
the initscript by hand.

FIXME: Document stacked runlevels

The default startup uses the runlevels "boot", "sysinit" and "default", in that 
order. Shutdown uses the "shutdown" runlevel.


# Syntax of Service Scripts

Service scripts are shell scripts. OpenRC aims at using only the standardized 
POSIX sh subset for portability reasons. The default interpreter (build-time 
toggle) is /bin/sh, so using for example mksh is not a problem.

OpenRC has been tested with busybox sh, ash, dash, bash, mksh, zsh and possibly 
others. Using busybox sh has been difficult as it replaces commands with 
builtins that don't offer the expected features.

The interpreter for initscripts is #!/sbin/openrc-run
Not using this interpreter will break the use of dependencies and is not 
supported. (iow: if you insist on using #!/bin/sh you're on your own)

A "depend" function declares the dependencies of this service script.
All scripts must have start/stop/status functions, but defaults are provided.
Extra functions can be added easily:

extra_commands="checkconfig"
checkconfig() {
	doSomething
}

This exports the checkconfig function so that "/etc/init.d/someservice 
checkconfig" will be available, and it "just" runs this function.

While commands defined in extra_commands are always available, commands
defined in extra_started_commands will only work when the service is started
and those defined in extra_stopped_commands will only work when the service is
stopped. This can be used for implementing graceful reload and similar
behaviour.

Adding a restart function will not work, this is a design decision within 
OpenRC. Since there may be dependencies involved (e.g. network -> apache) a 
restart function is in general not going to work. 
restart is internally mapped to stop() + start() (plus handling dependencies).
If a service needs to behave differently when it is being restarted vs
started or stopped, it should test the $RC_CMD variable, for example:

    [ "$RC_CMD" = restart ] && do_something


# The Depend Function

This function declares the dependencies for a service script. This
determines the order the service scripts start.

depend() {
	need net
	use dns logger netmount
	want coolservice
}

"need" declares a hard dependency - net always needs to be started before this 
	service does
"use" is a soft dependency - if dns, logger or netmount is in this runlevel 
	start it before, but we don't care if it's not in this runlevel.
	"want" is between need and use - try to start coolservice if it is
	installed on the system, regardless of whether it is in the
	runlevel, but we don't care if it starts.
"before" declares that we need to be started before another service
"after" declares that we need to be started after another service, without 
	creating a dependency (so on calling stop the two are independent)
"provide" allows multiple implementations to provide one service type, e.g.:
	'provide cron' is set in all cron-daemons, so any one of them started 
	satisfies a cron dependency
"keyword" allows platform-specific overrides, e.g. "keyword -lxc" makes this 
	service script a noop in lxc containers. Useful for things like keymaps, 
	module loading etc. that are either platform-specific or not available 
	in containers/virtualization/...

FIXME: Anything missing in this list?

# The Default Functions

All service scripts are assumed to have the following functions:

start()
stop()
status()

There are default implementations in rc/sh/openrc-run.sh - this allows very 
compact service scripts. These functions can be overridden per service script as 
needed.

The default functions assume the following variables to be set in the service 
script:

command=
command_args=
pidfile=

Thus the 'smallest' service scripts can be half a dozen lines long

# The Magic of Conf.d

Most service scripts need default values. It would be fragile to
explicitly source some arbitrary files. By convention openrc-run will source
the matching file in /etc/conf.d/ for any script in /etc/init.d/

This allows you to set random startup-related things easily. Example:

conf.d/foo:
START_OPTS="--extraparameter sausage"

init.d/foo:
start() {
	/usr/sbin/foo-daemon ${STARTOPTS}
}

The big advantage of this split is that most of the time editing of the init 
script can be avoided.

# Start-Stop-Daemon

OpenRC has its own modified version of s-s-d, which is historically related and 
mostly syntax-compatible to Debian's s-s-d, but has been rewritten from scratch.

It helps with starting daemons, backgrounding, creating PID files and many 
other convenience functions related to managing daemons.

# /etc/rc.conf

This file manages the default configuration for OpenRC, and it has examples of 
per-service-script variables.

Among these are rc_parallel (for parallelized startup), rc_log (logs all boot 
messages to a file), and a few others.

# ulimit and CGroups

Setting ulimit and nice values per service can be done through the rc_ulimit 
variable.

Under Linux, OpenRC can optionally use CGroups for process management.
By default each service script's processes are migrated to their own CGroup.

By changing certain values in the conf.d file limits can be enforced per 
service. It is easy to find orphan processes of a service that persist after 
stop(), but by default these will NOT be terminated.
To change this add rc_cgroup_cleanup="yes" in the conf.d files for services 
where you desire this functionality.

# Caching

For performance reasons OpenRC keeps a cache of pre-parsed initscript metadata
(e.g. depend). The default location for this is /${RC_SVCDIR}/cache.

The cache uses mtime to check for file staleness. Should any service script
change it'll re-source the relevant files and update the cache

# Convenience functions

OpenRC has wrappers for many common output tasks in libeinfo.
This allows to print colour-coded status notices and other things.
To make the output consistent the bundled initscripts all use ebegin/eend to 
print nice messages.