Writing Init Scripts: Difference between revisions
(update link) |
Prabuanand (talk | contribs) (removed draft notice, cleaned up introduction, moved headings, added wikitags) |
||
(35 intermediate revisions by 11 users not shown) | |||
Line 1: | Line 1: | ||
This page provide you with some basic information on how to write your own [[OpenRC]] init scripts. Many of the current init.d scripts found in Alpine Linux are taken from Gentoo. If you want to save time you could search [https://packages.gentoo.org/categories Gentoo's repository] for an existing initscript for your service. | |||
{{Tip|OpenRC services can be supervised by [[#Using S6 as service supervisor|s6]], a small & secure supervision software suite.}} | |||
== Things to avoid == | |||
* Prefer standard OpenRC variables such as <code>command_args</code>, <code>command_user</code> etc. | |||
* Do not create unnecessary config variables like <code>FOO_OPTS</code>, <code>FOO_USER</code> etc. If you want to predefine the default value in init.d script, use common idiom <code>: ${command_user=foo}</code>. | |||
* Use snake_case for naming extra configuration variables (to be consistent with the OpenRC variables and other init scripts in Alpine). Do not prefix them with the service name, try to be consistent with existing init scripts (e.g. <code>cfgfile</code>, <code>cfgdir</code>, <code>logfile</code>, <code>cachedir</code>, <code>listen_on</code>, <code>start_wait</code>, …). | |||
< | Primary information about the OpenRC format can be found in the [https://manpages.org/openrc-run/8 OpenRC man page openrc-run] or [https://www.mankier.com/8/openrc-run openrc-run(8)] and on command line as follows: {{Cmd|$ doas apk add openrc-doc | ||
$ man openrc-run}} | |||
command="/usr/ | |||
command_args="-- | == Basic example == | ||
pidfile="/ | Every init.d script needs to start with a [https://en.wikipedia.org/wiki/Shebang_(Unix) shebang] like: | ||
<code>#!/sbin/openrc-run</code> | |||
</ | |||
A minimal example for services relying on OpenRC exclusively appear as follows :{{Cat|minimal-example|<nowiki>#!/sbin/openrc-run | |||
command=/path/to/command</nowiki>}} | |||
A more complete example is given below:{{Cat|basic-example|<nowiki>#!/sbin/openrc-run | |||
name=$RC_SVCNAME | |||
cfgfile="/etc/$RC_SVCNAME/$RC_SVCNAME.conf" | |||
command="/usr/bin/my_daemon" | |||
command_args="--my-daemon-args" | |||
command_user="my_system_user" | |||
pidfile="/run/$RC_SVCNAME/$RC_SVCNAME.pid" | |||
start_stop_daemon_args="--args-for-start-stop-daemon" | |||
command_background="yes" | |||
depend() { | |||
need net | |||
} | |||
start_pre() { | |||
checkpath --directory --owner $command_user:$command_user --mode 0775 \ | |||
/run/$RC_SVCNAME /var/log/$RC_SVCNAME | |||
} | |||
</nowiki>}} | |||
== start, stop, restart functions == | |||
OpenRC defined a few basic functions ie: start, stop, restart. These functions are defined by default but can be overwritten by defining your own set of functions. | |||
This is generally only necessary if you want to do something special which is not provided by the default start/stop/restart implementations. | |||
== | === start === | ||
<pre> | <pre> | ||
Line 31: | Line 60: | ||
</pre> | </pre> | ||
=== stop === | |||
<pre> | |||
stop() { | |||
ebegin "Stopping mydaemon" | |||
start-stop-daemon --stop \ | |||
--exec /usr/sbin/mydaemon \ | |||
--pidfile /var/run/mydaemon.pid | |||
eend $? | |||
} | |||
</pre> | |||
=== restart === | |||
<pre> | |||
restart() { | |||
ebegin "Restarting mydaemon" | |||
svc_stop | |||
svc_start | |||
eend $? | |||
} | |||
</pre> | |||
== Daemon, Forking, Logging == | |||
If your daemon supports running in the foreground, set <code>command_background="yes"</code> and add a <code>--no-fork</code> or <code>--foreground</code> option to <code>command_args</code>. This prevents the daemon from forking itself into the background, so OpenRC can handle backgrounding. | |||
When you use <code>command_background="yes"</code>, you must also set a <code>pidfile</code>. This allows OpenRC to track and manage the daemon process correctly. | |||
If your daemon does not support running in the foreground, you can use <code>start-stop-daemon</code> directly in your <code>start()</code> function to launch the service and manage forking and pidfiles manually. | |||
For logging, use a <code>logfile</code> variable if your daemon supports it, or redirect output in your <code>start()</code> function. | |||
Example for a daemon that supports foreground mode: | |||
<pre> | |||
command_args="--no-fork --logfile /var/log/my_daemon.log" | |||
command_background="yes" | |||
pidfile="/run/my_daemon.pid" | |||
</pre> | |||
Example for a daemon that does not support foreground mode, using <code>start-stop-daemon</code>: | |||
<pre> | |||
start() { | |||
ebegin "Starting mydaemon" | |||
start-stop-daemon --start \ | |||
--exec /usr/bin/mydaemon \ | |||
--pidfile /run/mydaemon.pid \ | |||
--background \ | |||
--make-pidfile \ | |||
-- \ | |||
--logfile /var/log/mydaemon.log | |||
eend $? | |||
} | |||
</pre> | |||
== Using S6 as service supervisor == | |||
OpenRC services can be supervised by [https://www.skarnet.org/software/s6/ s6], a small & secure supervision software suite. | |||
* Install the and configure the <code>s6-scan</code> service to start on system boot. | |||
* Exclude <code>start()</code>, <code>stop()</code> and <code>status()</code> functions in order for s6 supervision to work reliably. OpenRC has built-in equivalent functions which invoke the necessary s6 commands. | |||
* Include a <code>depend()</code> stanza to ensure that the <code>s6-svscan</code> service is already running. | |||
* Add a <code>start_pre()</code> stanza to symlink the service directory into the scan directory, because the <code>/etc/init.d/bootmisc</code> scripts cleans out the <code>/run</code> directory on system boot. | |||
{{Cat|minimal-s6-example|<nowiki>#!/sbin/openrc-run | |||
name="foo" | |||
supervisor="s6" | |||
s6_service_path="${RC_SVCDIR}/s6-scan/${name}" | |||
depend() { | |||
need s6-svscan | |||
} | |||
start_pre() { | |||
if [ ! -L "${RC_SVC_DIR}/s6-scan/${name}" ]; then | |||
ln -s "/path/to/${name}/service/dir" "${RC_SVCDIR}/s6-scan/${name}" | |||
fi | |||
} | |||
... | |||
</nowiki>}} | |||
Rest of the basic example could be omitted, but that would most probably leave you with an non working initd script. | |||
== See also == | |||
* [https://github.com/OpenRC/openrc/blob/master/service-script-guide.md Official Service Script Writing Guide] | |||
* [https://wiki.gentoo.org/wiki/Handbook:X86/Working/Initscripts#Writing_initscripts Gentoo's wiki] | |||
[[Category:Booting]] | [[Category:Booting]] |
Latest revision as of 07:41, 19 September 2025
This page provide you with some basic information on how to write your own OpenRC init scripts. Many of the current init.d scripts found in Alpine Linux are taken from Gentoo. If you want to save time you could search Gentoo's repository for an existing initscript for your service.
Things to avoid
- Prefer standard OpenRC variables such as
command_args
,command_user
etc. - Do not create unnecessary config variables like
FOO_OPTS
,FOO_USER
etc. If you want to predefine the default value in init.d script, use common idiom: ${command_user=foo}
. - Use snake_case for naming extra configuration variables (to be consistent with the OpenRC variables and other init scripts in Alpine). Do not prefix them with the service name, try to be consistent with existing init scripts (e.g.
cfgfile
,cfgdir
,logfile
,cachedir
,listen_on
,start_wait
, …).
Primary information about the OpenRC format can be found in the OpenRC man page openrc-run or openrc-run(8) and on command line as follows:
$ doas apk add openrc-doc $ man openrc-run
Basic example
Every init.d script needs to start with a shebang like:
#!/sbin/openrc-run
A minimal example for services relying on OpenRC exclusively appear as follows :
Contents of minimal-example
A more complete example is given below:
Contents of basic-example
start, stop, restart functions
OpenRC defined a few basic functions ie: start, stop, restart. These functions are defined by default but can be overwritten by defining your own set of functions. This is generally only necessary if you want to do something special which is not provided by the default start/stop/restart implementations.
start
start() { ebegin "Starting mydaemon" start-stop-daemon --start \ --exec /usr/sbin/mydaemon \ --pidfile /var/run/mydaemon.pid \ -- \ --args-for-mydaemon eend $? }
stop
stop() { ebegin "Stopping mydaemon" start-stop-daemon --stop \ --exec /usr/sbin/mydaemon \ --pidfile /var/run/mydaemon.pid eend $? }
restart
restart() { ebegin "Restarting mydaemon" svc_stop svc_start eend $? }
Daemon, Forking, Logging
If your daemon supports running in the foreground, set command_background="yes"
and add a --no-fork
or --foreground
option to command_args
. This prevents the daemon from forking itself into the background, so OpenRC can handle backgrounding.
When you use command_background="yes"
, you must also set a pidfile
. This allows OpenRC to track and manage the daemon process correctly.
If your daemon does not support running in the foreground, you can use start-stop-daemon
directly in your start()
function to launch the service and manage forking and pidfiles manually.
For logging, use a logfile
variable if your daemon supports it, or redirect output in your start()
function.
Example for a daemon that supports foreground mode:
command_args="--no-fork --logfile /var/log/my_daemon.log" command_background="yes" pidfile="/run/my_daemon.pid"
Example for a daemon that does not support foreground mode, using start-stop-daemon
:
start() { ebegin "Starting mydaemon" start-stop-daemon --start \ --exec /usr/bin/mydaemon \ --pidfile /run/mydaemon.pid \ --background \ --make-pidfile \ -- \ --logfile /var/log/mydaemon.log eend $? }
Using S6 as service supervisor
OpenRC services can be supervised by s6, a small & secure supervision software suite.
- Install the and configure the
s6-scan
service to start on system boot. - Exclude
start()
,stop()
andstatus()
functions in order for s6 supervision to work reliably. OpenRC has built-in equivalent functions which invoke the necessary s6 commands. - Include a
depend()
stanza to ensure that thes6-svscan
service is already running. - Add a
start_pre()
stanza to symlink the service directory into the scan directory, because the/etc/init.d/bootmisc
scripts cleans out the/run
directory on system boot.
Contents of minimal-s6-example
Rest of the basic example could be omitted, but that would most probably leave you with an non working initd script.