From: "William Hubbs" <williamh@gentoo.org>
To: gentoo-commits@lists.gentoo.org
Subject: [gentoo-commits] proj/openrc:master commit in: /
Date: Mon, 8 Jan 2018 20:07:09 +0000 (UTC) [thread overview]
Message-ID: <1515441552.c2bd33e4838eb56bebe2707f6ca6bd05e9df5b24.williamh@OpenRC> (raw)
commit: c2bd33e4838eb56bebe2707f6ca6bd05e9df5b24
Author: Michael Orlitzky <michael <AT> orlitzky <DOT> com>
AuthorDate: Mon Sep 4 21:58:09 2017 +0000
Commit: William Hubbs <williamh <AT> gentoo <DOT> org>
CommitDate: Mon Jan 8 19:59:12 2018 +0000
URL: https://gitweb.gentoo.org/proj/openrc.git/commit/?id=c2bd33e4
service-script-guide.md: new guide for service script authors.
This fixes #162.
service-script-guide.md | 381 ++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 381 insertions(+)
diff --git a/service-script-guide.md b/service-script-guide.md
new file mode 100644
index 00000000..5806b808
--- /dev/null
+++ b/service-script-guide.md
@@ -0,0 +1,381 @@
+This document is aimed at upstream and distribution developers who
+write OpenRC service scripts, either for their own projects, or for
+the packages they maintain. It contains advice, suggestions, tips,
+tricks, hints, and counsel; cautions, warnings, heads-ups,
+admonitions, proscriptions, enjoinders, and reprimands.
+
+It is intended to prevent common mistakes that are found "in the wild"
+by pointing out those mistakes and suggesting alternatives. Each
+good/bad thing that you should/not do has a section devoted to it. We
+don't consider anything exotic, and assume that you will use
+start-stop-daemon to manage a fairly typical long-running UNIX
+process.
+
+# Don't write your own start/stop functions
+
+OpenRC is capable of stopping and starting most daemons based on the
+information that you give it. For a well-behaved daemon that
+backgrounds itself and writes its own PID file by default, the
+following OpenRC variables are likely all that you'll need:
+
+ * command
+ * command_args
+ * pidfile
+
+Given those three pieces of information, OpenRC will be able to start
+and stop the daemon on its own. The following is taken from an
+[OpenNTPD](http://www.openntpd.org/) service script:
+
+```sh
+command="/usr/sbin/ntpd"
+
+# The special RC_SVCNAME variable contains the name of this service.
+pidfile="/run/${RC_SVCNAME}.pid"
+command_args="-p ${pidfile}"
+```
+
+If the daemon runs in the foreground by default but has options to
+background itself and to create a pidfile, then you'll also need
+
+ * command_args_background
+
+That variable should contain the flags needed to background your
+daemon, and to make it write a PID file. Take for example the
+following snippet of an
+[NRPE](https://github.com/NagiosEnterprises/nrpe) service script:
+
+```sh
+command="/usr/bin/nrpe"
+command_args="--config=/etc/nagios/nrpe.cfg"
+command_args_background="--daemon"
+pidfile="/run/${RC_SVCNAME}.pid"
+```
+
+Since NRPE runs as *root* by default, it needs no special permissions
+to write to `/run/nrpe.pid`. OpenRC takes care of starting and
+stopping the daemon with the appropriate arguments, even passing the
+`--daemon` flag during startup to force NRPE into the background (NRPE
+knows how to write its own PID file).
+
+But what if the daemon isn't so well behaved? What if it doesn't know
+how to background itself or create a pidfile? If it can do neither,
+then use,
+
+ * command_background=true
+
+which will additionally pass `--make-pidfile` to start-stop-daemon,
+causing it to create the `$pidfile` for you (rather than the daemon
+itself being responsible for creating the PID file).
+
+If your daemon doesn't know how to change its own user or group, then
+you can tell start-stop-daemon to launch it as an unprivileged user
+with
+
+ * command_user="user:group"
+
+Finally, if your daemon always forks into the background but fails to
+create a PID file, then your only option is to use
+
+ * procname
+
+With `procname`, OpenRC will try to find the running daemon by
+matching the name of its process. That's not so reliable, but daemons
+shouldn't background themselves without creating a PID file in the
+first place. The next example is part of the [CA NetConsole
+Daemon](https://oss.oracle.com/projects/cancd/) service script:
+
+```sh
+command="/usr/sbin/cancd"
+command_args="-p ${CANCD_PORT}
+ -l ${CANCD_LOG_DIR}
+ -o ${CANCD_LOG_FORMAT}"
+command_user="cancd"
+
+# cancd daemonizes itself, but doesn't write a PID file and doesn't
+# have an option to run in the foreground. So, the best we can do
+# is try to match the process name when stopping it.
+procname="cancd"
+```
+
+To recap, in order of preference:
+
+ 1. If the daemon backgrounds itself and creates its own PID file, use
+ `pidfile`.
+ 2. If the daemon does not background itself (or has an option to run
+ in the foreground) and does not create a PID file, then use
+ `command_background=true` and `pidfile`.
+ 3. If the daemon backgrounds itself and does not create a PID file,
+ use `procname` instead of `pidfile`. But, if your daemon has the
+ option to run in the foreground, then you should do that instead
+ (that would be the case in the previous item).
+ 4. The last case, where the daemon does not background itself but
+ does create a PID file, doesn't make much sense. If there's a way
+ to disable the daemon's PID file (or, to write it straight into the
+ garbage), then do that, and use `command_background=true`.
+
+# Reloading your daemon's configuration
+
+Many daemons will reload their configuration files in response to a
+signal. Suppose your daemon will reload its configuration in response
+to a `SIGHUP`. It's possible to add a new "reload" command to your
+service script that performs this action. First, tell the service
+script about the new command.
+
+```sh
+extra_started_commands="reload"
+```
+
+We use `extra_started_commands` as opposed to `extra_commands` because
+the "reload" action is only valid while the daemon is running (that
+is, started). Now, start-stop-daemon can be used to send the signal to
+the appropriate process (assuming you've defined the `pidfile`
+variable elsewhere):
+
+```sh
+reload() {
+ ebegin "Reloading ${RC_SVCNAME}"
+ start-stop-daemon --signal HUP --pidfile "${pidfile}"
+ eend $?
+}
+```
+
+# Don't restart/reload with a broken config
+
+Often, users will start a daemon, make some configuration change, and
+then attempt to restart the daemon. If the recent configuration change
+contains a mistake, the result will be that the daemon is stopped but
+then cannot be started again (due to the configuration error). It's
+possible to prevent that situation with a function that checks for
+configuration errors, and a combination of the `start_pre` and
+`stop_pre` hooks.
+
+```sh
+checkconfig() {
+ # However you want to check this...
+}
+
+start_pre() {
+ # If this isn't a restart, make sure that the user's config isn't
+ # busted before we try to start the daemon (this will produce
+ # better error messages than if we just try to start it blindly).
+ #
+ # If, on the other hand, this *is* a restart, then the stop_pre
+ # action will have ensured that the config is usable and we don't
+ # need to do that again.
+ if [ "${RC_CMD}" != "restart" ] ; then
+ checkconfig || return $?
+ fi
+}
+
+stop_pre() {
+ # If this is a restart, check to make sure the user's config
+ # isn't busted before we stop the running daemon.
+ if [ "${RC_CMD}" = "restart" ] ; then
+ checkconfig || return $?
+ fi
+}
+```
+
+To prevent a *reload* with a broken config, keep it simple:
+
+```sh
+reload() {
+ checkconfig || return $?
+ ebegin "Reloading ${RC_SVCNAME}"
+ start-stop-daemon --signal HUP --pidfile "${pidfile}"
+ eend $?
+}
+```
+
+# PID files should be writable only by root
+
+PID files must be writable only by *root*, which means additionally
+that they must live in a *root*-owned directory.
+
+Some daemons run as an unprivileged user account, and create their PID
+files (as the unprivileged user) in a path like
+`/run/foo/foo.pid`. That can usually be exploited by the unprivileged
+user to kill *root* processes, since when a service is stopped, *root*
+usually sends a SIGTERM to the contents of the PID file (which are
+controlled by the unprivileged user). The main warning sign for that
+problem is using `checkpath` to set ownership on the directory
+containing the PID file. For example,
+
+```sh
+# BAD BAD BAD BAD BAD BAD BAD BAD
+start_pre() {
+ # Ensure that the pidfile directory is writable by the foo user/group.
+ checkpath --directory --mode 0700 --owner foo:foo "/run/foo"
+}
+# BAD BAD BAD BAD BAD BAD BAD BAD
+```
+
+If the *foo* user owns `/run/foo`, then he can put whatever he wants
+in the `/run/foo/foo.pid` file. Even if *root* owns the PID file, the
+*foo* user can delete it and replace it with his own. To avoid
+security concerns, the PID file must be created as *root* and live in
+a *root*-owned directory. If your daemon is responsible for forking
+and writing its own PID file but the PID file is still owned by the
+unprivileged runtime user, then you may have an upstream issue.
+
+Once the PID file is being created as *root* (before dropping
+privileges), it can be written directly to a *root*-owned
+directory. Typically this will be `/run` on Linux, and `/var/run`
+elsewhere. For example, the *foo* daemon might write
+`/run/foo.pid`. No calls to checkpath are needed. Note: there is
+nothing technically wrong with using a directory structure like
+`/run/foo/foo.pid`, so long as *root* owns the PID file and the
+directory containing it.
+
+Ideally (see "Upstream your service scripts"), your service script
+will be integrated upstream and the build system will determine
+which of `/run` or `/var/run` is appropriate. For example,
+
+```sh
+pidfile="@piddir@/${RC_SVCNAME}.pid"
+```
+
+A decent example of this is the [Nagios core service
+script](https://github.com/NagiosEnterprises/nagioscore/blob/master/openrc-init.in),
+where the full path to the PID file is specified at build-time.
+
+# Don't let the user control the PID file location
+
+It's usually a mistake to let the end user control the PID file
+location through a conf.d variable, for a few reasons:
+
+ 1. When the PID file path is controlled by the user, you need to
+ ensure that its parent directory exists and is writable. This
+ adds unnecessary code to the service script.
+
+ 2. If the PID file path changes while the service is running, then
+ you'll find yourself unable to stop the service.
+
+ 3. The directory that should contain the PID file is best determined
+ by the upstream build system (see "Upstream your service scripts").
+ On Linux, the preferred location these days is `/run`. Other systems
+ still use `/var/run`, though, and a `./configure` script is the
+ best place to decide which one you want.
+
+ 4. Nobody cares where the PID file is located, anyway.
+
+Since OpenRC service names must be unique, a value of
+
+```sh
+pidfile="/run/${RC_SVCNAME}.pid"
+```
+
+guarantees that your PID file has a unique name.
+
+# Upstream your service scripts (for distribution developers)
+
+The ideal place for an OpenRC service script is **upstream**. Much like
+systemd services, a well-crafted OpenRC service script should be
+distribution-agnostic, and the best place for it is upstream. Why? For
+two reasons. First, having it upstream means that there's a single
+authoritative source for improvements. Second, a few paths in every
+service script are dependent upon flags passed to the build system. For
+example,
+
+```sh
+command=/usr/bin/foo
+```
+
+in an autotools-based build system should really be
+
+```sh
+command=@bindir@/foo
+```
+
+so that the user's value of `--bindir` is respected. If you keep the
+service script in your own distribution's repository, then you have to
+keep the command path and package synchronized yourself, and that's no
+fun.
+
+# Be wary of "need net" dependencies
+
+There are two things you need to know about "need net" dependencies:
+
+ 1. They are not satisfied by the loopback interface, so "need net"
+ requires some *other* interface to be up.
+
+ 2. Depending on the value of `rc_depend_strict` in `rc.conf`, the
+ "need net" will be satisfied when either *any* non-loopback
+ interface is up, or when *all* non-loopback interfaces are up.
+
+The first item means that "need net" is wrong for daemons that are
+happy with `0.0.0.0`, and the second point means that "need net" is
+wrong for daemons that need a particular (for example, the WAN)
+interface. We'll consider the two most common users of "need net";
+network clients who access some network resource, and network servers
+who provide them.
+
+## Network clients
+
+Network clients typically want the WAN interface to be up. That may
+tempt you to depend on the WAN interface; but first, you should ask
+yourself a question: does anything bad happen if the WAN interface is
+not available? In other words, if the administrator wants to disable
+the WAN, should the service be stopped? Usually the answer to that
+question is "no," and in that case, you should forego the "net"
+dependency entirely.
+
+Suppose, for example, that your service retrieves virus signature
+updates from the internet. In order to do its job correctly, it needs
+a (working) internet connection. However, the service itself does not
+require the WAN interface to be up: if it is, great; otherwise, the
+worst that will happen is that a "server unavailable" warning will be
+logged. The signature update service will not crash, and—perhaps more
+importantly—you don't want it to terminate if the administrator turns
+off the WAN interface for a second.
+
+## Network servers
+
+Network servers are generally easier to handle than their client
+counterparts. Most server daemons listen on `0.0.0.0` (all addresses)
+by default, and are therefore satisfied to have the loopback interface
+present and operational. OpenRC ships with the loopback service in the
+*boot* runlevel, and therefore most server daemons require no further
+network dependencies.
+
+The exceptions to this rule are those daemons who produce negative
+side-effects when the WAN is unavailable. For example, the Nagios
+server daemon will generate "the sky is falling" alerts for as long as
+your monitored hosts are unreachable. So in that case, you should
+require some other interface (often the WAN) to be up. A "need"
+dependency would be appropriate, because you want Nagios to be
+stopped before the network is taken down.
+
+If your daemon can optionally be configured to listen on a particular
+interface, then please see the "Depending on a particular interface"
+section.
+
+## Depending on a particular interface
+
+If you need to depend on one particular interface, usually it's not
+easy to determine programmatically what that interface is. For
+example, if your *sshd* daemon listens on `192.168.1.100` (rather than
+`0.0.0.0`), then you have two problems:
+
+ 1. Parsing `sshd_config` to figure that out; and
+
+ 2. Determining which network service name corresponds to the
+ interface for `192.168.1.100`.
+
+It's generally a bad idea to parse config files in your service
+scripts, but the second problem is the harder one. Instead, the most
+robust (i.e. the laziest) approach is to make the user specify the
+dependency when he makes a change to sshd_config. Include something
+like the following in the service configuration file,
+
+```sh
+# Specify the network service that corresponds to the "bind" setting
+# in your configuration file. For example, if you bind to 127.0.0.1,
+# this should be set to "net.lo" which provides the loopback interface.
+rc_need="net.lo"
+```
+
+This is a sensible default for daemons that are happy with `0.0.0.0`,
+but lets the user specify something else, like `rc_need="net.wan"` if
+he needs it. The burden is on the user to determine the appropriate
+service whenever he changes the daemon's configuration file.
next reply other threads:[~2018-01-09 2:04 UTC|newest]
Thread overview: 150+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-01-08 20:07 William Hubbs [this message]
-- strict thread matches above, loose matches on Subject: below --
2018-11-02 23:24 [gentoo-commits] proj/openrc:master commit in: / William Hubbs
2018-10-23 22:14 William Hubbs
2018-10-23 22:00 William Hubbs
2018-10-23 22:00 William Hubbs
2018-10-22 23:09 William Hubbs
2018-06-28 18:33 William Hubbs
2018-06-28 18:03 William Hubbs
2018-06-17 17:46 William Hubbs
2018-06-15 23:07 William Hubbs
2018-06-15 18:01 William Hubbs
2018-06-05 22:38 William Hubbs
2018-06-05 22:38 William Hubbs
2018-06-05 21:28 William Hubbs
2018-05-31 21:54 William Hubbs
2018-03-12 2:43 William Hubbs
2018-02-28 22:32 William Hubbs
2018-01-24 23:44 William Hubbs
2018-01-11 16:59 William Hubbs
2018-01-10 19:29 William Hubbs
2018-01-08 21:34 William Hubbs
2017-12-07 18:53 William Hubbs
2017-10-25 20:10 William Hubbs
2017-10-24 15:43 William Hubbs
2017-10-13 21:11 William Hubbs
2017-10-13 16:38 William Hubbs
2017-10-12 23:55 William Hubbs
2017-10-02 21:59 William Hubbs
2017-10-02 16:22 William Hubbs
2017-09-16 18:27 William Hubbs
2017-09-16 18:27 William Hubbs
2017-09-15 20:32 William Hubbs
2017-09-14 15:57 William Hubbs
2017-09-07 17:25 William Hubbs
2017-09-06 22:33 William Hubbs
2017-08-24 16:45 William Hubbs
2017-08-16 17:16 William Hubbs
2017-07-24 22:29 William Hubbs
2017-07-13 22:51 William Hubbs
2017-07-13 22:51 William Hubbs
2017-07-11 20:13 William Hubbs
2017-07-11 19:57 William Hubbs
2017-06-12 15:41 William Hubbs
2017-06-07 17:15 William Hubbs
2017-05-16 0:00 William Hubbs
2017-05-12 3:01 William Hubbs
2017-04-19 22:38 William Hubbs
2017-04-17 17:49 William Hubbs
2017-03-31 15:37 William Hubbs
2017-03-15 22:31 William Hubbs
2017-03-12 18:56 William Hubbs
2017-03-10 19:33 William Hubbs
2017-01-26 23:07 William Hubbs
2016-12-21 17:51 William Hubbs
2016-12-20 18:34 William Hubbs
2016-09-28 0:40 William Hubbs
2016-09-27 17:26 William Hubbs
2016-09-09 0:28 William Hubbs
2016-08-30 14:16 William Hubbs
2016-08-30 14:16 William Hubbs
2016-08-25 22:35 William Hubbs
2016-07-25 18:54 William Hubbs
2016-06-10 21:12 William Hubbs
2016-05-24 19:10 William Hubbs
2016-05-24 18:14 William Hubbs
2016-05-24 18:05 William Hubbs
2016-05-19 18:37 William Hubbs
2016-02-09 21:42 William Hubbs
2016-01-19 22:33 William Hubbs
2016-01-14 17:37 William Hubbs
2016-01-13 17:04 William Hubbs
2015-12-11 22:49 William Hubbs
2015-12-09 23:58 William Hubbs
2015-12-08 19:12 William Hubbs
2015-12-08 19:12 William Hubbs
2015-12-06 0:14 William Hubbs
2015-12-04 19:52 William Hubbs
2015-10-08 21:15 William Hubbs
2015-10-08 18:34 William Hubbs
2015-07-10 18:26 William Hubbs
2015-06-19 14:56 William Hubbs
2015-05-29 6:11 Mike Frysinger
2015-05-13 21:07 William Hubbs
2015-05-11 23:46 William Hubbs
2015-05-02 0:03 William Hubbs
2015-05-01 21:19 William Hubbs
2015-04-26 15:31 William Hubbs
2015-04-25 23:36 William Hubbs
2015-04-25 1:01 William Hubbs
2015-04-25 0:41 William Hubbs
2015-04-22 22:43 William Hubbs
2015-04-22 22:14 William Hubbs
2015-04-22 22:05 William Hubbs
2015-04-22 21:17 William Hubbs
2015-04-22 20:55 William Hubbs
2015-04-22 20:40 William Hubbs
2015-04-22 20:09 William Hubbs
2015-04-22 20:09 William Hubbs
2015-01-23 18:57 William Hubbs
2014-10-20 20:59 William Hubbs
2014-10-20 20:59 William Hubbs
2014-08-22 19:10 William Hubbs
2014-08-17 5:14 ` William Hubbs
2014-08-17 21:07 William Hubbs
2014-08-22 19:10 ` William Hubbs
2014-08-16 22:18 William Hubbs
2014-08-22 19:10 ` William Hubbs
2014-08-11 18:18 William Hubbs
2014-08-22 19:10 ` William Hubbs
2014-07-10 14:05 William Hubbs
2014-07-01 12:33 William Hubbs
2014-06-24 1:54 William Hubbs
2014-04-10 0:58 William Hubbs
2014-01-23 18:04 William Hubbs
2013-08-24 23:00 William Hubbs
2013-08-14 6:08 William Hubbs
2013-08-14 5:17 William Hubbs
2013-07-16 18:56 William Hubbs
2013-07-16 18:56 William Hubbs
2013-06-24 21:31 Robin H. Johnson
2013-05-07 22:08 William Hubbs
2013-05-07 19:40 William Hubbs
2012-11-02 21:41 William Hubbs
2012-10-18 15:14 William Hubbs
2012-09-23 16:12 William Hubbs
2012-07-09 2:05 William Hubbs
2012-05-22 15:14 William Hubbs
2012-03-02 19:55 Robin H. Johnson
2012-02-12 19:38 Christian Ruppert
2012-01-25 19:04 Robin H. Johnson
2012-01-14 20:11 William Hubbs
2012-01-07 0:02 William Hubbs
2011-12-09 23:49 William Hubbs
2011-11-25 21:40 William Hubbs
2011-11-23 14:38 William Hubbs
2011-10-16 15:36 Christian Ruppert
2011-09-08 20:13 William Hubbs
2011-09-08 18:31 William Hubbs
2011-09-02 20:26 William Hubbs
2011-09-01 22:21 William Hubbs
2011-09-01 15:35 William Hubbs
2011-07-13 22:54 William Hubbs
2011-06-24 17:47 William Hubbs
2011-06-20 2:39 William Hubbs
2011-05-16 22:05 Mike Frysinger
2011-04-19 17:19 Robin H. Johnson
2011-04-16 1:02 William Hubbs
2011-04-12 13:49 William Hubbs
2011-03-22 5:49 William Hubbs
2011-02-22 2:59 Robin H. Johnson
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1515441552.c2bd33e4838eb56bebe2707f6ca6bd05e9df5b24.williamh@OpenRC \
--to=williamh@gentoo.org \
--cc=gentoo-commits@lists.gentoo.org \
--cc=gentoo-dev@lists.gentoo.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox