Compare commits

..

73 Commits

Author SHA1 Message Date
William Hubbs
d1161c8aae update ChangeLog 2016-08-30 09:11:28 -05:00
William Hubbs
528bfa13f9 another news typo fix 2016-08-30 09:08:17 -05:00
Doug Freed
5f1daa6f30 modules-load: handle comments better
This handles comments without a trailing space after the comment
character.

Reported-By: josef64
2016-08-26 15:31:59 -04:00
William Hubbs
0445bc13f8 typo fix 2016-08-26 13:36:53 -04:00
Doug Freed
73d024228d version 0.21.5 2016-08-26 13:36:11 -04:00
William Hubbs
4809bc249f update changelog 2016-08-25 17:45:58 -05:00
William Hubbs
1478552071 Update news file
Add information on modules-load service and more explanation about
dealing with the rc -> openrc and runscript -> openrc-run transitions.
2016-08-25 17:36:12 -05:00
William Hubbs
8aa0b5b8a9 init.d: add modules-load to ignore patterns 2016-08-25 17:02:14 -05:00
William Hubbs
c8059c8474 modules-load.d: cleanups
Move list of directories to a local variable and create the fn variable
to use for an individual file name rather than using path.
2016-08-25 16:58:46 -05:00
William Hubbs
b888f1a8e2 Add modules-load.d support 2016-08-25 16:58:46 -05:00
William Hubbs
6e0bd2deb1 openrc-run: make runscript warning respect quiet option
X-Gentoo-Bug: 591414
X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=591414
2016-08-25 11:51:26 -05:00
William Hubbs
cdc42d91db version 0.21.4 2016-08-25 11:48:05 -05:00
William Hubbs
bd4cafbbf3 Update ChangeLog 2016-07-31 14:05:41 -05:00
William Hubbs
61e211c1c4 init.d: initial service adjustments for docker support
Add -docker keyword to the same scripts that have -lxc keyword.
2016-07-31 13:50:05 -05:00
William Hubbs
40d3795fba librc: fix Docker auto detection
The original auto detection of Docker containers assumed the presence of
a container environment variable. However, Docker-1.12 does not
implement this, and I'm not sure which versions of docker implemented
it.

The new test is for the presence of a file named .dockerenv in the
root directory.
2016-07-31 13:50:05 -05:00
Doug Freed
fa39271d7a rc-logger: refuse to cat TMPLOG into itself
This prevents an infinite loop in case somebody decides to set
rc_log_path to match TMPLOG.
2016-07-31 13:50:05 -05:00
Julian Ospald
0077e54146 Build: fix hardcoded pkg-config invocation
This fixes #89.
2016-07-31 13:50:05 -05:00
William Hubbs
871fa56baa version 0.21.3 2016-07-31 13:49:33 -05:00
William Hubbs
53f6bd3690 update changelog 2016-07-06 12:24:06 -05:00
William Hubbs
6074cbd651 hwclock: always use --noadjfile if available
When we use the --utc or --localtime switch, also use --noadjfile if it
is available. This means hwclock will not use a drift file.

X-Gentoo-Bug: 584722
X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=584722
2016-07-06 12:22:49 -05:00
William Hubbs
8b9ea8b9e6 version 0.21.2 2016-07-06 12:20:32 -05:00
William Hubbs
c47b497483 update changelog 2016-06-28 16:34:42 -05:00
Benda Xu
977811563d Fix PATH for Prefix.
1. remove default /bin:/sbin:/usr/bin:/usr/sbin
2. PKG_PREFIX should be defaulted to $(PREFIX)/usr
3. LOCAL_PREFIX should be defaulted to $(PREFIX)/usr/local

X-Gentoo-Bug:583634
X-Gentoo-Bug-URL:https://bugs.gentoo.org/show_bug.cgi?id=583634
2016-06-28 14:37:47 -05:00
William Hubbs
47aa0b93cd fstabinfo/mountinfo: ensure /etc/fstab exists before calling setmntent
This is based on a patch by A. Wilcox <awilfox.gentoo@foxkit.us>.

X-Gentoo-Bug: 478226
X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=478226

X-Gentoo-Bug: 478226
X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=478226
2016-06-28 14:37:47 -05:00
William Hubbs
f680c89c26 version 0.21.1 2016-06-28 14:35:20 -05:00
William Hubbs
5bfb7d6c77 Update ChangeLog 2016-05-24 14:02:35 -05:00
William Hubbs
12c8248b5f update news for 0.21 2016-05-24 13:06:29 -05:00
William Hubbs
820ef6dab6 supervise-daemon: clarify documentation about configuring daemon not to fork 2016-05-24 12:55:50 -05:00
William Hubbs
87884db667 Make deprecation warnings for rc and runscript more visible
These warnings were inserted in verbose only mode in OpenRC-0.13.A
Now, we are making them more visible in preparation for removing these
compatibility binaries in the future.
2016-05-24 11:24:10 -05:00
William Hubbs
94077d264e supervise-daemon: log the exit code or signal when a child process dies 2016-05-23 11:10:51 -05:00
William Hubbs
3351c8b4c3 supervise-daemon.sh: add support for chroot variable 2016-05-19 17:59:40 -05:00
William Hubbs
a8214af2fe start-stop-daemon.sh: fix regression in chroot support
The support for the chroot variable was broken in 0.16, this fixes that
breakage.
2016-05-19 17:58:14 -05:00
William Hubbs
9a372812c7 guide.md: typo fix
This fixes #86.
2016-05-19 13:36:43 -05:00
Jason Zaman
3fa9015b8e rc-selinux: access check was backwards 2016-05-13 12:52:21 -05:00
William Hubbs
3b5a8b331e supervise-daemon: add pam service file 2016-05-13 12:05:23 -05:00
Anthony G. Basile
b3a04e797e runlevels/Makefile: add support for runlevel ‘nonetwork’
Traditional System V reserves runlevel 2 for multiuser with no
networking.  We add support for this which is already defined in
the inittab as

    l2:2:wait:/sbin/rc nonetwork

X-Gentoo-Bug: 533828
X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=533828

Signed-off-by: Anthony G. Basile <blueness@gentoo.org>
2016-05-12 17:49:56 -04:00
William Hubbs
92e2f2c7cc killprocs: remove calls to sleep
X-Gentoo-Bug: 487084
X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=487084
2016-05-05 17:02:39 -05:00
William Hubbs
ad23d5b8db openrc-run: clean up runscript deprecation message 2016-05-04 18:17:58 -05:00
William Hubbs
62410eaf4b add daemon supervisor
The supervise-daemon process is meant to be a lightweight supervisor
which can monitor and restart a daemon if it crashes.
2016-04-27 11:13:50 -05:00
William Hubbs
fd80b6fc67 localmount/netmount: clean up critical mount processing
Fix a typo and do not fail if a path in critical_mounts is not listed as
a critical mount does not get mounted.
2016-04-26 12:43:50 -05:00
William Hubbs
5d130cc45c localmount/netmount: allow mount points to be marked critical
In previous releases, we either treated no mount points as critical or
all of them.

Now both localmount and netmount support a critical_mounts setting. If
mount points listed in this setting fail to mount, localmount and
netmount will fail.
2016-04-25 12:04:34 -05:00
William Hubbs
1c3c2cf6d8 netmount: fix mounting on Linux
Before this commit, on Linux, we were always trying to mount file
systems marked with _netdev, even when the previous mount command
failed. Now, we do not run the second mount if the first fails.

X-Gentoo-Bug: 579876
X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=579876
2016-04-15 11:30:44 -05:00
Mike Gilbert
171e856ec8 start-stop-daemon: Allow group read/write when creating output files
This allows for better interaction with inherited ACL entries.
This fixes #84.

X-Gentoo-Bug: 577362
X-Gentoo-Bug-URL: https://bugs.gentoo.org/577362
2016-04-11 11:11:59 -05:00
Dustin C. Hatch
beaa71df0a binfmt.sh: use read in raw mode
The read builtin in most shells will interpret backslash characters
as escapes, and they are lost when reading binfmt files line-by-line.
This causes magic strings containing backslashes to be mangled and
become invalid, resulting in erroneous 'invalid entry' messages.

The -r option to read disables special handling of backslashes and
keeps all lines intact.

X-Gentoo-Bug: 575114
X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=575114
2016-02-19 15:25:53 -06:00
William Hubbs
7eaf71176b Fix rc_env_allow wildcard usage
Before this commit, using * in rc_env_allow did not work.

This fixes #60.
2016-02-12 12:44:52 -06:00
Mike Frysinger
2c1f6a16e1 sysfs: mount pstore when available 2016-02-09 15:39:43 -06:00
Patrick Lauer
e82653782e Add a basic OpenRC users guide
X-Gentoo-Bug: 513024
X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=513024
2016-02-09 15:30:46 -06:00
William Hubbs
e52b5f59c2 savecache: stop saving nettree
Netifrc is no longer part of OpenRC, so we shouldn't save its dep tree
as part of savecache.

This should have been removed when netifrc was split out. also, it
might be related to the following bug.

X-Gentoo-Bug: 563720
X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=563720
2016-01-28 17:06:25 -06:00
William Hubbs
8a7e4d38a7 rc-service: add --ifinactive and --ifnotstarted flags
X-Gentoo-Bug: 523174
X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=523174
2016-01-28 12:57:11 -06:00
William Hubbs
47dd5e37cb add back deprecation warnings lost during refactoring 2016-01-22 12:46:29 -06:00
William Hubbs
e277ae57ef fix tests
X-Gentoo-Bug: 572602
X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=572602
2016-01-22 12:07:13 -06:00
William Hubbs
69f052b611 librc: Complain when a real and virtual service have the same name 2016-01-21 15:58:03 -06:00
William Hubbs
e4eacf02ca openrc-run: in verbose mode, log execution of the shell script
This is to show when openrc-run runs the openrc-run.sh script; it is
used for debugging.
2016-01-20 11:20:40 -06:00
Colin Booth
30c3561b6b sh/s6.sh: update s6-svc syntax to be valid for 2.2.0.0+
The s6-svc syntax changed for wait-up, wait-ready, wait-down, and
wait-finished. This changes the s6 handling script to use the current
valid syntax.

This fixes #65.
2016-01-19 16:52:58 -06:00
Manuel Rüger
5f2850366e Fix typo
This fixes #70.
2016-01-19 16:30:41 -06:00
Gokturk Yuksek
1cb7eec31f conf.d/bootmisc: typo fix: s/dmesc/dmesg/
This fixes #72.
2016-01-19 16:22:34 -06:00
William Hubbs
cd7883d25d localmount: Allow users to control whether errors are ignored
X-Gentoo-Bug: 572138
X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=572138
2016-01-19 13:34:04 -06:00
Doug Freed
62b49b2a3a rc: remove use of magic constant and allow OpenVZ to drop to shell
OpenVZ has had console support for a long time now; allow them to use it
to drop to a shell during interactive boot.
2016-01-19 00:09:20 -06:00
Doug Freed
4c814a0a28 librc: handle rc_sys="prefix" even if we weren't built with a prefix
This probably isn't needed, but it mimics old behavior.
2016-01-19 00:09:20 -06:00
Doug Freed
36dde4e7f2 librc: fix handling the nothing special case for rc_sys 2016-01-19 00:09:20 -06:00
Doug Freed
649f63d882 librc: move system detection code into rc_sys and use it
This fixes an issue where librc code was calling code that only existed
in the rc binary.

This reverts commits 8addd79 and 9f6e056

This fixes #75.
2016-01-19 00:09:20 -06:00
William Hubbs
55a28f5d25 Revert "rc: make get_systype similar to the old rc_sys function"
This reverts commit f79a7a7be1.
2016-01-18 23:40:20 -06:00
William Hubbs
6c09421375 Revert "librc: fix librc-depend functions to call rc_sys"
This reverts commit 73482cf13a.
2016-01-18 23:40:03 -06:00
William Hubbs
79359f77cc fix bsd build
X-Gentoo-Bug: 572068
X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=572068
2016-01-18 16:06:39 -06:00
William Hubbs
f79a7a7be1 rc: make get_systype similar to the old rc_sys function 2016-01-18 15:50:59 -06:00
William Hubbs
73482cf13a librc: fix librc-depend functions to call rc_sys 2016-01-18 15:09:31 -06:00
William Hubbs
0910c455d3 src/rc/Makefile: fix make depend target 2016-01-14 13:33:05 -06:00
William Hubbs
f5e06bc55a include rc.h properly in source files
We were attempting to include rc.h in rc-misc.h instead of the source
files where it should be included.
2016-01-14 12:52:32 -06:00
William Hubbs
e7ae08c38d version 0.21 2016-01-14 11:35:18 -06:00
William Hubbs
6da0abc085 fix selinux build
X-Gentoo-Bug: 571798
X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=571798
2016-01-14 11:29:24 -06:00
William Hubbs
b34df9dd81 fix selinux build 2016-01-13 20:11:06 -06:00
William Hubbs
6f02069746 Add LANG, LC_MESSAGES and TERM to the environment whitelist 2016-01-13 19:34:22 -06:00
William Hubbs
d4c7207ef3 fix seg fault 2016-01-13 19:30:19 -06:00
63 changed files with 1983 additions and 873 deletions

1250
ChangeLog

File diff suppressed because it is too large Load Diff

View File

@@ -38,7 +38,7 @@ Who:
When: 1.0
Why: Depprecated in favor of extra_commands, extra_started_commands
Why: Deprecated in favor of extra_commands, extra_started_commands
and extra_stopped_commands.
Who:
@@ -47,7 +47,7 @@ Who:
When: 1.0
Why: Depprecated in favor of executable scripts in @SYSCONFDIR@/local.d
Why: Deprecated in favor of executable scripts in @SYSCONFDIR@/local.d
Who:

View File

@@ -1,3 +1,3 @@
NAME= openrc
VERSION= 0.20.5
VERSION= 0.21.5
PKG= ${NAME}-${VERSION}

27
NEWS.md
View File

@@ -3,6 +3,33 @@
This file will contain a list of notable changes for each release. Note
the information in this file is in reverse order.
## OpenRC-0.21
This version adds a daemon supervisor which can start daemons and
restart them if they crash. See supervise-daemon-guide.md in the
distribution for details on its use.
It is now possible to mark certain mount points as critical. If these
mount points are unable to be mounted, localmount or netmount will fail.
This is handled in /etc/conf.d/localmount and /etc/conf.d/netmount. See
these files for the setup.
The deprecation messages in 0.13.x for runscript and rc are now
made visible in preparation for the removal of these binaries in 1.0.
The steps you should take to get rid of these warnings is to run openrc
in initialization steps instead of rc and change the shebang lines in
service scripts to refer to "openrc-run" instead of "runscript".
In 0.21.4, a modules-load service was added. This works like the
equivalent service in systemd. It looks for files named *.conf first in
/usr/lib/modules-load.d, then /run/modules-load.d, then
/etc/modules-load.d. These files contain a list of modules, one per
line, which should be loaded into the kernel. If a file name appears in
/run/modules-load.d, it overrides a file of the same name in
/usr/lib/modules-load.d. A file appearing in /etc/modules-load.d
overrides a file of the same name in both previous directories.
## OpenRC-0.19
This version adds a net-online service. By default, this

View File

@@ -9,7 +9,7 @@ wipe_tmp="YES"
# This may be useful if you need the kernel boot log afterwards
log_dmesg="YES"
# Save the previous dmesg log to dmesc.old
# Save the previous dmesg log to dmesg.old
# This may be useful if you need to compare the current boot to the
# previous one.
#previous_dmesg=no

View File

@@ -2,8 +2,9 @@
# This could be useful for some NFS related work.
#no_umounts="/dir1:/var/dir2"
#
# Ignore errors when mounting local file systems.
# This should be left alone unless you know what you are doing. If it is
# set to yes, not only will we allow mount failures, but we will ignore
# syntax errors in fstab.
#ignore_mount_errors="NO"
# Mark certain mount points as critical.
# This contains aspace separated list of mount points which should be
# considered critical. If one of these mount points cannot be mounted,
# localmount will fail.
# By default, this is empty.
#critical_mounts="/home /var"

View File

@@ -38,3 +38,10 @@
# other words, please change it to be more suited to your system.
#
rc_need="net"
#
# Mark certain mount points as critical.
# This contains aspace separated list of mount points which should be
# considered critical. If one of these mount points cannot be mounted,
# netmount will fail.
# By default, this is empty.
#critical_mounts="/home /var"

251
guide.md Normal file
View File

@@ -0,0 +1,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.

1
init.d/.gitignore vendored
View File

@@ -1,4 +1,5 @@
binfmt
modules-load
bootmisc
fsck
hostname

View File

@@ -19,10 +19,10 @@ SRCS-FreeBSD= hostid.in moused.in newsyslog.in pf.in rarpd.in rc-enabled.in \
rpcbind.in savecore.in syslogd.in
# These are FreeBSD specific
SRCS-FreeBSD+= adjkerntz.in devd.in dumpon.in encswap.in ipfw.in \
mixer.in nscd.in powerd.in syscons.in
modules.in modules-load.in mixer.in nscd.in powerd.in syscons.in
SRCS-Linux= binfmt.in devfs.in dmesg.in hwclock.in consolefont.in keymaps.in \
killprocs.in modules.in mount-ro.in mtab.in numlock.in \
killprocs.in modules.in modules-load.in mount-ro.in mtab.in numlock.in \
procfs.in net-online.in sysfs.in termencoding.in tmpfiles.dev.in
# Generic BSD scripts

View File

@@ -15,7 +15,7 @@ depend()
{
after procfs
use modules devfs
keyword -openvz -prefix -systemd-nspawn -vserver -lxc
keyword -docker -lxc -openvz -prefix -systemd-nspawn -vserver
}
start()

View File

@@ -15,7 +15,7 @@ depend()
{
need localmount termencoding
after hotplug bootmisc modules
keyword -openvz -prefix -systemd-nspawn -uml -vserver -xenu -lxc
keyword -docker -lxc -openvz -prefix -systemd-nspawn -uml -vserver -xenu
}
start()

View File

@@ -15,7 +15,7 @@ depend()
{
provide dev-mount
before dev
keyword -prefix -systemd-nspawn -vserver -lxc
keyword -docker -lxc -prefix -systemd-nspawn -vserver
}
mount_dev()

View File

@@ -14,7 +14,7 @@ description="Set the dmesg level for a cleaner boot"
depend()
{
before dev modules
keyword -lxc -prefix -systemd-nspawn -vserver
keyword -docker -lxc -prefix -systemd-nspawn -vserver
}
start()

View File

@@ -16,7 +16,7 @@ _IFS="
depend()
{
use dev clock modules
keyword -jail -openvz -prefix -systemd-nspawn -timeout -vserver -lxc -uml
keyword -docker -jail -lxc -openvz -prefix -systemd-nspawn -timeout -vserver -uml
}
_abort() {

View File

@@ -12,7 +12,7 @@
description="Sets the hostname of the machine."
depend() {
keyword -prefix -systemd-nspawn -lxc
keyword -docker -lxc -prefix -systemd-nspawn
}
start()

View File

@@ -35,7 +35,7 @@ depend()
else
before *
fi
keyword -openvz -prefix -systemd-nspawn -uml -vserver -xenu -lxc
keyword -docker -lxc -openvz -prefix -systemd-nspawn -uml -vserver -xenu
}
setupopts()
@@ -69,6 +69,16 @@ _hwclock()
return 1
}
get_noadjfile()
{
if ! yesno $clock_adjfile; then
# Some implementations don't handle adjustments
if LC_ALL=C hwclock --help 2>&1 | grep -q "\-\-noadjfile"; then
echo --noadjfile
fi
fi
}
start()
{
local retval=0 errstr=""
@@ -91,16 +101,16 @@ start()
fi
# Always set the kernel's time zone.
_hwclock --systz $utc_cmd $clock_args
_hwclock --systz $utc_cmd $(get_noadjfile) $clock_args
: $(( retval += $? ))
if [ -e /etc/adjtime ] && yesno $clock_adjfile; then
_hwclock --adjust $utc_cmd
_hwclock --adjust $utc_cmd $(get_noadjfile)
: $(( retval += $? ))
fi
if yesno ${clock_hctosys:-YES}; then
_hwclock --hctosys $utc_cmd $clock_args
_hwclock --hctosys $utc_cmd $(get_noadjfile) $clock_args
: $(( retval += $? ))
fi
@@ -122,14 +132,7 @@ stop()
ebegin "Setting hardware clock using the system clock" "[$utc]"
if ! yesno $clock_adjfile; then
# Some implementations don't handle adjustments
if LC_ALL=C hwclock --help 2>&1 | grep -q "\-\-noadjfile"; then
utc_cmd="$utc_cmd --noadjfile"
fi
fi
_hwclock --systohc $utc_cmd $clock_args
_hwclock --systohc $utc_cmd $(get_noadjfile) $clock_args
retval=$?
eend $retval "Failed to sync clocks"
@@ -144,5 +147,5 @@ save()
show()
{
setupopts
hwclock --show "$utc_cmd" $clock_args
hwclock --show "$utc_cmd" $(get_noadjfile) $clock_args
}

View File

@@ -15,7 +15,7 @@ depend()
{
need localmount termencoding
after bootmisc
keyword -openvz -prefix -systemd-nspawn -uml -vserver -xenu -lxc
keyword -docker -lxc -openvz -prefix -systemd-nspawn -uml -vserver -xenu
}
start()

View File

@@ -20,10 +20,8 @@ start()
{
ebegin "Terminating remaining processes"
killall5 -15 ${killall5_opts}
sleep 1
eend 0
ebegin "Killing remaining processes"
killall5 -9 ${killall5_opts}
sleep 1
eend 0
}

View File

@@ -16,13 +16,13 @@ depend()
need fsck
use lvm modules mtab
after lvm modules
keyword -jail -prefix -systemd-nspawn -vserver -lxc
keyword -docker -jail -lxc -prefix -systemd-nspawn -vserver
}
start()
{
# Mount local filesystems in /etc/fstab.
local types="noproc" x= no_netdev= rc=
local critical= types="noproc" x= no_netdev= rc=
for x in $net_fs_list $extra_net_fs_list; do
types="${types},no${x}"
done
@@ -37,13 +37,17 @@ start()
mount -at "$types" $no_netdev
eend $? "Some local filesystem failed to mount"
rc=$?
if [ "$RC_UNAME" != Linux ]; then
if [ -z "$critical_mounts" ]; then
rc=0
elif yesno "${ignore_mount_errors:-NO}"; then
if [ $rc -ne 0 ]; then
ewarn "localmount: errors detected, but ignored"
else
for x in ${critical_mounts}; do
fstabinfo -q $x || continue
if ! mountinfo -q $x; then
critical=x
eerror "Failed to mount $x"
fi
rc=0
done
[ -z "$critical" ] && rc=0
fi
return $rc
}

72
init.d/modules-load.in Normal file
View File

@@ -0,0 +1,72 @@
#!@SBINDIR@/openrc-run
# Copyright (c) 2016 The OpenRC Authors.
# See the Authors file at the top-level directory of this distribution and
# https://github.com/OpenRC/openrc/blob/master/AUTHORS
#
# This file is part of OpenRC. It is subject to the license terms in
# the LICENSE file found in the top-level directory of this
# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE
# This file may not be copied, modified, propagated, or distributed
# except according to the terms contained in the LICENSE file.
description="Loads a list of modules from systemd-compatible locations."
depend()
{
keyword -docker -lxc -openvz -prefix -systemd-nspawn -vserver
}
find_modfiles()
{
local dirs="/usr/lib/modules-load.d /run/modules-load.d /etc/modules-load.d"
local basenames files fn x y
for x in $dirs; do
[ ! -d $x ] && continue
for y in $x/*.conf; do
[ -f $y ] && basenames="${basenames}\n${y##*/}"
done
done
basenames=$(printf "$basenames" | sort -u)
for x in $basenames; do
for y in $dirs; do
[ -r $y/$x ] &&
fn=$y/$x
done
files="$files $fn"
done
echo $files
}
load_modules()
{
local file m modules rc x
file=$1
[ -z "$file" ] && return 0
while read m x; do
case $m in
\;*) continue ;;
\#*) continue ;;
*) modules="$modules $m"
;;
esac
done < $file
for x in $modules; do
ebegin "Loading module $x"
case "$RC_UNAME" in
FreeBSD) kldload "$x"; rc=$? ;;
linux) modprobe -q "$x"; rc=$? ;;
*) ;;
esac
eend $rc "Failed to load $x"
done
}
start()
{
local x
files=$(find_modfiles)
for x in $files; do
load_modules $x
done
return 0
}

View File

@@ -14,7 +14,8 @@ description="Loads a user defined list of kernel modules."
depend()
{
use isapnp
keyword -openvz -prefix -systemd-nspawn -vserver -lxc
want modules-load
keyword -docker -lxc -openvz -prefix -systemd-nspawn -vserver
}
start()

View File

@@ -14,7 +14,7 @@ description="Re-mount filesytems read-only for a clean reboot."
depend()
{
need killprocs savecache
keyword -openvz -prefix -systemd-nspawn -vserver -lxc
keyword -docker -lxc -openvz -prefix -systemd-nspawn -vserver
}
start()

View File

@@ -15,7 +15,7 @@ depend()
{
after modules
need sysfs
keyword -jail -lxc -openvz -prefix -systemd-nspawn -uml -vserver
keyword -docker -jail -lxc -openvz -prefix -systemd-nspawn -uml -vserver
}
get_interfaces()

View File

@@ -24,7 +24,7 @@ depend()
want $mywant
use afc-client amd openvpn
use dns
keyword -jail -prefix -systemd-nspawn -vserver -lxc
keyword -docker -jail -lxc -prefix -systemd-nspawn -vserver
}
start()
@@ -37,13 +37,22 @@ start()
ebegin "Mounting network filesystems"
mount -at $fs
rc=$?
if [ "$RC_UNAME" = Linux ]; then
if [ "$RC_UNAME" = Linux ] && [ $rc = 0 ]; then
mount -a -O _netdev
rc=$?
fi
ewend $rc "Could not mount all network filesystems"
if [ "$RC_UNAME" != Linux ]; then
if [ -z "$critical_mounts" ]; then
rc=0
else
for x in ${critical_mounts}; do
fstabinfo -q $x || continue
if ! mountinfo -q $x; then
critical=x
eerror "Failed to mount $x"
fi
done
[ -z "$critical" ] && rc=0
fi
return $rc
}
@@ -72,7 +81,7 @@ stop()
retval=$?
eoutdent
if [ "$RC_UNAME" = Linux ]; then
if [ "$RC_UNAME" = Linux ] && [ $retval = 0 ]; then
umount -a -O _netdev
retval=$?
fi

View File

@@ -16,7 +16,7 @@ ttyn=${rc_tty_number:-${RC_TTY_NUMBER:-12}}
depend()
{
need localmount
keyword -openvz -prefix -systemd-nspawn -vserver -lxc
keyword -docker -lxc -openvz -prefix -systemd-nspawn -vserver
}
_setleds()

View File

@@ -15,7 +15,7 @@ depend()
{
use modules devfs
need localmount
keyword -openvz -prefix -systemd-nspawn -vserver -lxc
keyword -docker -lxc -openvz -prefix -systemd-nspawn -vserver
}
start()

View File

@@ -14,7 +14,7 @@ description="Mount the root fs read/write"
depend()
{
need fsck
keyword -jail -openvz -prefix -systemd-nspawn -vserver -lxc
keyword -docker -jail -lxc -openvz -prefix -systemd-nspawn -vserver
}
start()

View File

@@ -49,7 +49,7 @@ start()
fi
ebegin "Saving dependency cache"
local rc=0 save=
for x in deptree depconfig shutdowntime softlevel nettree rc.log; do
for x in deptree depconfig shutdowntime softlevel rc.log; do
[ -e "$RC_SVCDIR/$x" ] && save="$save $RC_SVCDIR/$x"
done
if [ -n "$save" ]; then

View File

@@ -12,7 +12,7 @@
depend()
{
before localmount
keyword -jail -openvz -prefix -systemd-nspawn -vserver -lxc
keyword -docker -jail -lxc -openvz -prefix -systemd-nspawn -vserver
}
start()

View File

@@ -12,7 +12,7 @@
depend()
{
need localmount
keyword -jail -openvz -prefix -systemd-nspawn -vserver -lxc
keyword -docker -jail -lxc -openvz -prefix -systemd-nspawn -vserver
}
start()

View File

@@ -15,7 +15,7 @@ depend()
{
before *
provide clock
keyword -openvz -prefix -systemd-nspawn -uml -vserver -xenu -lxc
keyword -docker -lxc -openvz -prefix -systemd-nspawn -uml -vserver -xenu
}
# swclock is an OpenRC built in

View File

@@ -15,7 +15,7 @@ sysfs_opts=nodev,noexec,nosuid
depend()
{
keyword -lxc -prefix -systemd-nspawn -vserver
keyword -docker -lxc -prefix -systemd-nspawn -vserver
}
mount_sys()
@@ -88,6 +88,15 @@ mount_misc()
fi
fi
# Setup Kernel Support for persistent storage
if [ -d /sys/fs/pstore ] && ! mountinfo -q /sys/fs/pstore; then
if grep -qs 'pstore$' /proc/filesystems; then
ebegin "Mounting persistent storage (pstore) filesystem"
mount -t pstore pstore -o ${sysfs_opts} /sys/fs/pstore
eend $?
fi
fi
# setup up kernel support for efivarfs
# slightly complicated, as if it's build as a module but NOT yet loaded,
# it will NOT appear in /proc/filesystems yet

View File

@@ -16,7 +16,7 @@ ttyn=${rc_tty_number:-${RC_TTY_NUMBER:-12}}
depend()
{
keyword -lxc -openvz -prefix -systemd-nspawn -uml -vserver -xenu
keyword -docker -lxc -openvz -prefix -systemd-nspawn -uml -vserver -xenu
use root
after bootmisc
}

View File

@@ -15,7 +15,7 @@ description="Initializes the random number generator."
depend()
{
need localmount
keyword -jail -lxc -openvz -prefix -systemd-nspawn
keyword -docker -jail -lxc -openvz -prefix -systemd-nspawn
}
save_seed()

View File

@@ -6,7 +6,7 @@ MAN3= einfo.3 \
rc_config.3 rc_deptree.3 rc_find_pids.3 rc_plugin_hook.3 \
rc_runlevel.3 rc_service.3 rc_stringlist.3
MAN8= rc-service.8 rc-status.8 rc-update.8 openrc.8 openrc-run.8 \
service.8 start-stop-daemon.8
service.8 start-stop-daemon.8 supervise-daemon.8
ifeq (${OS},Linux)
MAN8 += rc-sstat.8

View File

@@ -95,10 +95,17 @@ String describing the service.
.It Ar description_$command
String describing the extra command.
.It Ar supervisor
Supervisor to use to monitor this daemon. If this is unset,
start-stop-daemon will be used. The only alternate supervisor we support
in this release is S6 from Skarnet software. To use this, set
Supervisor to use to monitor this daemon. If this is unset or invalid,
start-stop-daemon will be used.
Currently, we support s6 from scarnet software, and supervise-daemon
which is a light-weight supervisor internal to OpenRC.
To use s6, set
supervisor=s6.
or set
supervisor=supervise-daemon
to use supervise-daemon.
Note that supervise-daemon is still in early development, so it is
considered experimental.
.It Ar s6_service_path
The path to the s6 service directory if you are monitoring this service
with S6. The default is /var/svc.d/${RC_SVCNAME}.
@@ -112,10 +119,16 @@ List of arguments passed to start-stop-daemon when starting the daemon.
.It Ar command
Daemon to start or stop via
.Nm start-stop-daemon
or
.Nm supervise-daemon
if no start or stop function is defined by the service.
.It Ar command_args
List of arguments to pass to the daemon when starting via
.Nm start-stop-daemon .
.It Ar command_args_foreground
List of arguments to pass to the daemon when starting via
.Nm supervise-daemon .
to force the daemon to stay in the foreground
.It Ar command_background
Set this to "true", "yes" or "1" (case-insensitive) to force the daemon into
the background. This implies the "--make-pidfile" and "--pidfile" option of
@@ -123,6 +136,8 @@ the background. This implies the "--make-pidfile" and "--pidfile" option of
so the pidfile variable must be set.
.It Ar chroot
.Xr start-stop-daemon 8
and
.Xr supervise-daemon 8
will chroot into this path before writing the pid file or starting the daemon.
.It Ar pidfile
Pidfile to use for the above defined command.

View File

@@ -20,6 +20,14 @@
.Ar service cmd
.Op Ar ...
.Nm
.Op Fl I , -ifinactive
.Ar service cmd
.Op Ar ...
.Nm
.Op Fl N , -ifnotstarted
.Ar service cmd
.Op Ar ...
.Nm
.Fl e , -exists
.Ar service
.Nm
@@ -36,6 +44,13 @@ If
is given then
.Nm
returns 0 even if the service does not exist.
If
.Fl I , -ifinactive
or
.Fl N , -ifnotstarted
is given then
.Nm
returns 0 if the service exists but is in the wrong state.
.Pp
If given the
.Fl l , -list

142
man/supervise-daemon.8 Normal file
View File

@@ -0,0 +1,142 @@
.\" Copyright (c) 2007-2015 The OpenRC Authors.
.\" See the Authors file at the top-level directory of this distribution and
.\" https://github.com/OpenRC/openrc/blob/master/AUTHORS
.\"
.\" This file is part of OpenRC. It is subject to the license terms in
.\" the LICENSE file found in the top-level directory of this
.\" distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE
.\" This file may not be copied, modified, propagated, or distributed
.\" except according to the terms contained in the LICENSE file.
.\"
.Dd April 27, 2016
.Dt supervise-DAEMON 8 SMM
.Os OpenRC
.Sh NAME
.Nm supervise-daemon
.Nd starts a daemon and restarts it if it crashes
.Sh SYNOPSIS
.Nm
.Fl d , -chdir
.Ar path
.Fl e , -env
.Ar var=value
.Fl g , -group
.Ar group
.Fl I , -ionice
.Ar arg
.Fl k , -umask
.Ar value
.Fl N , -nicelevel
.Ar level
.Fl p , -pidfile
.Ar pidfile
.Fl u , -user
.Ar user
.Fl r , -chroot
.Ar chrootpath
.Fl 1 , -stdout
.Ar logfile
.Fl 2 , -stderr
.Ar logfile
.Fl S , -start
.Ar daemon
.Op Fl -
.Op Ar arguments
.Nm
.Fl K , -stop
.Ar daemon
.Fl p , -pidfile
.Ar pidfile
.Fl r , -chroot
.Ar chrootpath
.Sh DESCRIPTION
.Nm
provides a consistent method of starting, stopping and restarting
daemons. If
.Fl K , -stop
is not provided, then we assume we are starting the daemon.
.Nm
only works with daemons which do not fork. Also, it uses its own pid
file, so the daemon should not write a pid file, or the pid file passed
to
.Nm
should not be the one the daemon writes.
.Pp
Here are the options to specify the daemon and how it should start or stop:
.Bl -tag -width indent
.It Fl p , -pidfile Ar pidfile
When starting, we write a
.Ar pidfile
so we know which supervisor to stop. When stopping we only stop the pid(s)
listed in the
.Ar pidfile .
.It Fl u , -user Ar user Ns Op : Ns Ar group
Start the daemon as the
.Ar user
and update $HOME accordingly or stop daemons
owned by the user. You can optionally append a
.Ar group
name here also.
.It Fl v , -verbose
Print the action(s) that are taken just before doing them.
.Pp
The options are as follows:
.Bl -tag -width indent
.It Fl d , -chdir Ar path
chdir to this directory before starting the daemon.
.It Fl e , -env Ar VAR=VALUE
Set the environment variable VAR to VALUE.
.It Fl g , -group Ar group
Start the daemon as in the group.
.It Fl I , -ionice Ar class Ns Op : Ns Ar data
Modifies the IO scheduling priority of the daemon.
Class can be 0 for none, 1 for real time, 2 for best effort and 3 for idle.
Data can be from 0 to 7 inclusive.
.It Fl k , -umask Ar mode
Set the umask of the daemon.
.It Fl N , -nicelevel Ar level
Modifies the scheduling priority of the daemon.
.It Fl r , -chroot Ar path
chroot to this directory before starting the daemon. All other paths, such
as the path to the daemon, chdir and pidfile, should be relative to the chroot.
.It Fl u , -user Ar user
Start the daemon as the specified user.
.It Fl 1 , -stdout Ar logfile
Redirect the standard output of the process to logfile.
Must be an absolute pathname, but relative to the path optionally given with
.Fl r , -chroot .
The logfile can also be a named pipe.
.It Fl 2 , -stderr Ar logfile
The same thing as
.Fl 1 , -stdout
but with the standard error output.
.El
.Sh ENVIRONMENT
.Va SSD_NICELEVEL
can also set the scheduling priority of the daemon, but the command line
option takes precedence.
.Sh NOTE
.Nm
uses
.Xr getopt 3
to parse its options, which allows it to accept the `--' option which will
cause it to stop processing options at that point. Any subsequent arguments
are passed as arguments to the daemon to start and used when finding a daemon
to stop or signal.
.Sh SEE ALSO
.Xr chdir 2 ,
.Xr chroot 2 ,
.Xr getopt 3 ,
.Xr nice 2 ,
.Xr rc_find_pids 3
.Sh BUGS
.Nm
cannot stop an interpreted daemon that no longer exists without a pidfile.
.Sh HISTORY
.Nm
first appeared in Debian.
.Pp
This is a complete re-implementation with the process finding code in the
OpenRC library (librc, -lrc) so other programs can make use of it.
.Sh AUTHORS
.An William Hubbs <w.d.hubbs@gmail.com>

View File

@@ -3,4 +3,6 @@
ifeq (${MKPREFIX},yes)
CPPFLAGS+= -DPREFIX
PKG_PREFIX?= $(PREFIX)/usr
SED_EXTRA= -e '/_PATH=.*usr.bin/d'
endif

View File

@@ -13,7 +13,7 @@
_OS_SH= uname -s | tr '/' '-'
_OS:= $(shell ${_OS_SH})
OS?= ${_OS}
include ${MK}/os-${OS}.mk
include ${MK}/os-prefix.mk
include ${MK}/os-${OS}.mk
RC_LIB= /$(LIBNAME)/rc

View File

@@ -11,6 +11,7 @@
AR?= ar
CP?= cp
PKG_CONFIG?= pkg-config
ECHO?= echo
INSTALL?= install
RANLIB?= ranlib
@@ -26,7 +27,7 @@ ifeq (${MKPREFIX},yes)
UPREFIX= ${PREFIX}/usr
endif
endif
LOCAL_PREFIX= /usr/local
LOCAL_PREFIX= $(UPREFIX)/local
PICFLAG?= -fPIC

View File

@@ -1,6 +1,6 @@
ifeq (${MKTERMCAP},ncurses)
TERMCAP_CFLAGS:= $(shell pkg-config ncurses --cflags 2> /dev/null)
LTERMCAP:= $(shell pkg-config ncurses --libs 2> /dev/null)
TERMCAP_CFLAGS:= $(shell ${PKG_CONFIG} ncurses --cflags 2> /dev/null)
LTERMCAP:= $(shell ${PKG_CONFIG} ncurses --libs 2> /dev/null)
ifeq ($(LTERMCAP),)
LIBTERMCAP?= -lncurses
else

View File

@@ -3,6 +3,7 @@ include ../mk/net.mk
BOOT= bootmisc fsck hostname localmount loopback \
root swap swapfiles sysctl urandom ${BOOT-${OS}}
DEFAULT= local netmount
NONETWORK= local
SHUTDOWN= savecache ${SHUTDOWN-${OS}}
SYSINIT= ${SYSINIT-${OS}}
@@ -10,6 +11,7 @@ LEVELDIR= ${DESTDIR}/${SYSCONFDIR}/runlevels
SYSINITDIR= ${LEVELDIR}/sysinit
BOOTDIR= ${LEVELDIR}/boot
DEFAULTDIR= ${LEVELDIR}/default
NONETWORKDIR= ${LEVELDIR}/nonetwork
SHUTDOWNDIR= ${LEVELDIR}/shutdown
ifeq (${MKNET},yes)
@@ -72,6 +74,14 @@ install:
fi; \
ln -snf ${INITDIR}/"$$x" ${DEFAULTDIR}/"$$x" || exit $$?; done \
fi
if ! test -d "${NONETWORKDIR}"; then \
${INSTALL} -d ${NONETWORKDIR} || exit $$?; \
for x in ${NONETWORK}; do \
if test "${MKPREFIX}" = yes; then \
grep -q "keyword .*-prefix" ${INITFILES}/"$$x" && continue; \
fi; \
ln -snf ${INITDIR}/"$$x" ${NONETWORKDIR}/"$$x" || exit $$?; done \
fi
if ! test -d "${SHUTDOWNDIR}"; then \
${INSTALL} -d ${SHUTDOWNDIR} || exit $$?; \
for x in ${SHUTDOWN}; do \

View File

@@ -1,7 +1,8 @@
DIR= ${LIBEXECDIR}/sh
SRCS= init.sh.in functions.sh.in gendepends.sh.in \
openrc-run.sh.in rc-functions.sh.in tmpfiles.sh.in ${SRCS-${OS}}
INC= rc-mount.sh functions.sh rc-functions.sh s6.sh start-stop-daemon.sh
INC= functions.sh rc-mount.sh rc-functions.sh s6.sh start-stop-daemon.sh \
supervise-daemon.sh
BIN= gendepends.sh init.sh openrc-run.sh tmpfiles.sh ${BIN-${OS}}
INSTALLAFTER= _installafter

View File

@@ -22,7 +22,7 @@ apply_file() {
### FILE FORMAT ###
# See https://www.kernel.org/doc/Documentation/binfmt_misc.txt
while read line; do
while read -r line; do
LINENUM=$(( LINENUM+1 ))
case $line in
\#*) continue ;;

View File

@@ -154,6 +154,7 @@ start()
local func=ssd_start
case "$supervisor" in
s6) func=s6_start ;;
supervise-daemon) func=supervise_start ;;
?*)
ewarn "Invalid supervisor, \"$supervisor\", using start-stop-daemon"
;;
@@ -166,6 +167,7 @@ stop()
local func=ssd_stop
case "$supervisor" in
s6) func=s6_stop ;;
supervise-daemon) func=supervise_stop ;;
?*)
ewarn "Invalid supervisor, \"$supervisor\", using start-stop-daemon"
;;
@@ -178,6 +180,7 @@ status()
local func=ssd_status
case "$supervisor" in
s6) func=s6_status ;;
supervise-daemon) func=supervise_status ;;
?*)
ewarn "Invalid supervisor, \"$supervisor\", using start-stop-daemon"
;;
@@ -215,6 +218,7 @@ fi
# load service supervisor functions
sourcex "@LIBEXECDIR@/sh/s6.sh"
sourcex "@LIBEXECDIR@/sh/start-stop-daemon.sh"
sourcex "@LIBEXECDIR@/sh/supervise-daemon.sh"
# Set verbose mode
if yesno "${rc_verbose:-$RC_VERBOSE}"; then

View File

@@ -40,6 +40,7 @@ ssd_start()
fi
eval start-stop-daemon --start \
--exec $command \
${chroot:+--chroot} $chroot \
${procname:+--name} $procname \
${pidfile:+--pidfile} $pidfile \
${command_user+--user} $command_user \
@@ -47,6 +48,7 @@ ssd_start()
-- $command_args $command_args_background
if eend $? "Failed to start $RC_SVCNAME"; then
service_set_value "command" "${command}"
[ -n "${chroot}" ] && service_set_value "chroot" "${chroot}"
[ -n "${pidfile}" ] && service_set_value "pidfile" "${pidfile}"
[ -n "${procname}" ] && service_set_value "procname" "${procname}"
return 0
@@ -62,9 +64,11 @@ ssd_start()
ssd_stop()
{
local startcommand="$(service_get_value "command")"
local startchroot="$(service_get_value "chroot")"
local startpidfile="$(service_get_value "pidfile")"
local startprocname="$(service_get_value "procname")"
command="${startcommand:-$command}"
chroot="${startchroot:-$chroot}"
pidfile="${startpidfile:-$pidfile}"
procname="${startprocname:-$procname}"
[ -n "$command" -o -n "$procname" -o -n "$pidfile" ] || return 0
@@ -73,7 +77,7 @@ ssd_stop()
${retry:+--retry} $retry \
${command:+--exec} $command \
${procname:+--name} $procname \
${pidfile:+--pidfile} $pidfile \
${pidfile:+--pidfile} $chroot$pidfile \
${stopsig:+--signal} $stopsig
eend $? "Failed to stop $RC_SVCNAME"

55
sh/supervise-daemon.sh Normal file
View File

@@ -0,0 +1,55 @@
# start / stop / status functions for supervise-daemon
# Copyright (c) 2016 The OpenRC Authors.
# See the Authors file at the top-level directory of this distribution and
# https://github.com/OpenRC/openrc/blob/master/AUTHORS
#
# This file is part of OpenRC. It is subject to the license terms in
# the LICENSE file found in the top-level directory of this
# distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE
# This file may not be copied, modified, propagated, or distributed
# except according to the terms contained in the LICENSE file.
supervise_start()
{
if [ -z "$command" ]; then
ewarn "The command variable is undefined."
ewarn "There is nothing for ${name:-$RC_SVCNAME} to start."
return 1
fi
ebegin "Starting ${name:-$RC_SVCNAME}"
eval supervise-daemon --start \
${chroot:+--chroot} $chroot \
${pidfile:+--pidfile} $pidfile \
${command_user+--user} $command_user \
$supervise_daemon_args \
$command \
-- $command_args $command_args_foreground
rc=$?
if [ $rc = 0 ]; then
[ -n "${chroot}" ] && service_set_value "chroot" "${chroot}"
[ -n "${pidfile}" ] && service_set_value "pidfile" "${pidfile}"
fi
eend $rc "failed to start $RC_SVCNAME"
}
supervise_stop()
{
local startchroot="$(service_get_value "chroot")"
local startpidfile="$(service_get_value "pidfile")"
chroot="${startchroot:-$chroot}"
pidfile="${startpidfile:-$pidfile}"
[ -n "$pidfile" ] || return 0
ebegin "Stopping ${name:-$RC_SVCNAME}"
supervise-daemon --stop \
${pidfile:+--pidfile} $chroot$pidfile \
${stopsig:+--signal} $stopsig
eend $? "Failed to stop $RC_SVCNAME"
}
supervise_status()
{
_status
}

View File

@@ -285,6 +285,9 @@ detect_container(const char *systype)
return RC_SYS_RKT;
else if (file_regex("/proc/1/environ", "container=systemd-nspawn"))
return RC_SYS_SYSTEMD_NSPAWN;
else if (exists("/.dockerenv"))
return RC_SYS_DOCKER;
/* old test, I'm not sure when this was valid. */
else if (file_regex("/proc/1/environ", "container=docker"))
return RC_SYS_DOCKER;
#endif

1
src/rc/.gitignore vendored
View File

@@ -5,6 +5,7 @@ rc-update
runscript
service
start-stop-daemon
supervise-daemon
einfon
einfo
ewarnn

View File

@@ -3,7 +3,7 @@ SRCS= checkpath.c do_e.c do_mark_service.c do_service.c \
mountinfo.c openrc-run.c rc-abort.c rc.c \
rc-depend.c rc-logger.c rc-misc.c rc-plugin.c \
rc-service.c rc-status.c rc-update.c \
shell_var.c start-stop-daemon.c swclock.c _usage.c
shell_var.c start-stop-daemon.c supervise-daemon.c swclock.c _usage.c
ifeq (${MKSELINUX},yes)
SRCS+= rc-selinux.c
@@ -16,7 +16,8 @@ SBINDIR= ${PREFIX}/sbin
LINKDIR= ${LIBEXECDIR}
BINPROGS= rc-status
SBINPROGS = openrc openrc-run rc rc-service rc-update runscript service start-stop-daemon
SBINPROGS = openrc openrc-run rc rc-service rc-update runscript service \
start-stop-daemon supervise-daemon
RC_BINPROGS= einfon einfo ewarnn ewarn eerrorn eerror ebegin eend ewend \
eindent eoutdent esyslog eval_ecolors ewaitfile \
veinfo vewarn vebegin veend vewend veindent veoutdent \
@@ -74,6 +75,7 @@ install: all
if test "${MKPAM}" = pam; then \
${INSTALL} -d ${DESTDIR}${PAMDIR}; \
${INSTALL} -m ${PAMMODE} start-stop-daemon.pam ${DESTDIR}${PAMDIR}/start-stop-daemon; \
${INSTALL} -m ${PAMMODE} supervise-daemon.pam ${DESTDIR}${PAMDIR}/supervise-daemon; \
fi
check test::
@@ -136,6 +138,9 @@ rc-update: rc-update.o _usage.o rc-misc.o
start-stop-daemon: start-stop-daemon.o _usage.o rc-misc.o
${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDADD}
supervise-daemon: supervise-daemon.o _usage.o rc-misc.o
${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDADD}
service_get_value service_set_value get_options save_options: do_value.o rc-misc.o
${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDADD}

View File

@@ -178,6 +178,9 @@ int main(int argc, char **argv)
FILE *fp;
#endif
/* fail if there is no /etc/fstab */
if (!exists("/etc/fstab"))
eerrorx("/etc/fstab does not exist");
/* Ensure that we are only quiet when explicitly told to be */
unsetenv("EINFO_QUIET");

View File

@@ -297,6 +297,9 @@ getmntfile(const char *file)
struct mntent *ent = NULL;
FILE *fp;
if (!exists("/etc/fstab"))
return NULL;
fp = setmntent("/etc/fstab", "r");
while ((ent = getmntent(fp)))
if (strcmp(file, ent->mnt_dir) == 0)

View File

@@ -1106,6 +1106,7 @@ service_plugable(void)
int main(int argc, char **argv)
{
bool doneone = false;
bool runscript = false;
int retval, opt, depoptions = RC_DEP_TRACE;
RC_STRING *svc;
char path[PATH_MAX], lnk[PATH_MAX];
@@ -1123,7 +1124,7 @@ int main(int argc, char **argv)
applet = basename_c(argv[0]);
if (strcmp(applet, "runscript") == 0)
ewarnv("runscript is deprecated, please use openrc-run instead.");
runscript = true;
if (stat(argv[1], &stbuf) != 0) {
fprintf(stderr, "openrc-run `%s': %s\n",
@@ -1291,6 +1292,9 @@ int main(int argc, char **argv)
applet_list = rc_stringlist_new();
rc_stringlist_add(applet_list, applet);
if (runscript)
ewarn("%s uses runscript, please convert to openrc-run.", service);
/* Now run each option */
retval = EXIT_SUCCESS;
while (optind < argc) {

View File

@@ -247,6 +247,10 @@ rc_logger_open(const char *level)
logfile = rc_conf_value("rc_log_path");
if (logfile == NULL)
logfile = DEFAULTLOG;
if (!strcmp(logfile, TMPLOG)) {
eerror("Cowardly refusing to concatenate a logfile into itself.");
eerrorx("Please change rc_log_path to something other than %s to get rid of this message", TMPLOG);
}
if ((plog = fopen(logfile, "ae"))) {
if ((log = fopen(TMPLOG, "re"))) {

View File

@@ -370,7 +370,7 @@ void selinux_setup(char **argv)
* which will open the pty with initrc_devpts_t, if it doesnt exist,
* fall back to plain exec
*/
if (access("/usr/sbin/open_init_pty", X_OK)) {
if (!access("/usr/sbin/open_init_pty", X_OK)) {
if (execvp("/usr/sbin/open_init_pty", argv)) {
perror("execvp");
exit(-1);

View File

@@ -29,10 +29,12 @@
const char *applet = NULL;
const char *extraopts = NULL;
const char *getoptstring = "e:ilr:" getoptstring_COMMON;
const char *getoptstring = "e:ilr:IN" getoptstring_COMMON;
const struct option longopts[] = {
{ "exists", 1, NULL, 'e' },
{ "ifexists", 0, NULL, 'i' },
{ "ifinactive", 0, NULL, 'I' },
{ "ifnotstarted", 0, NULL, 'N' },
{ "list", 0, NULL, 'l' },
{ "resolve", 1, NULL, 'r' },
longopts_COMMON
@@ -40,6 +42,8 @@ const struct option longopts[] = {
const char * const longopts_help[] = {
"tests if the service exists or not",
"if the service exists then run the command",
"if the service is inactive then run the command",
"if the service is not started then run the command",
"list all available services",
"resolve the service name to an init script",
longopts_help_COMMON
@@ -56,7 +60,10 @@ int main(int argc, char **argv)
char *service;
RC_STRINGLIST *list;
RC_STRING *s;
RC_SERVICE state;
bool if_exists = false;
bool if_inactive = false;
bool if_notstarted = false;
applet = basename_c(argv[0]);
/* Ensure that we are only quiet when explicitly told to be */
@@ -77,6 +84,12 @@ int main(int argc, char **argv)
case 'i':
if_exists = true;
break;
case 'I':
if_inactive = true;
break;
case 'N':
if_notstarted = true;
break;
case 'l':
list = rc_services_in_runlevel(NULL);
if (TAILQ_FIRST(list) == NULL)
@@ -113,6 +126,11 @@ int main(int argc, char **argv)
return 0;
eerrorx("%s: service `%s' does not exist", applet, *argv);
}
state = rc_service_state(*argv);
if (if_inactive && ! (state & RC_SERVICE_INACTIVE))
return 0;
if (if_notstarted && (state & RC_SERVICE_STARTED))
return 0;
*argv = service;
execv(*argv, argv);
eerrorx("%s: %s", applet, strerror(errno));

View File

@@ -831,7 +831,7 @@ int main(int argc, char **argv)
}
if (strcmp(applet, "rc") == 0)
ewarnv("rc is deprecated, please use openrc instead.");
ewarn("rc is deprecated, please use openrc instead.");
newlevel = argv[optind++];
/* To make life easier, we only have the shutdown runlevel as
* nothing really needs to know that we're rebooting.

View File

@@ -1242,7 +1242,7 @@ int main(int argc, char **argv)
if (redirect_stdout) {
if ((stdout_fd = open(redirect_stdout,
O_WRONLY | O_CREAT | O_APPEND,
S_IRUSR | S_IWUSR)) == -1)
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)) == -1)
eerrorx("%s: unable to open the logfile"
" for stdout `%s': %s",
applet, redirect_stdout, strerror(errno));
@@ -1250,7 +1250,7 @@ int main(int argc, char **argv)
if (redirect_stderr) {
if ((stderr_fd = open(redirect_stderr,
O_WRONLY | O_CREAT | O_APPEND,
S_IRUSR | S_IWUSR)) == -1)
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)) == -1)
eerrorx("%s: unable to open the logfile"
" for stderr `%s': %s",
applet, redirect_stderr, strerror(errno));

726
src/rc/supervise-daemon.c Normal file
View File

@@ -0,0 +1,726 @@
/*
* supervise-daemon
* This is an experimental supervisor for daemons.
* It will start a deamon and make sure it restarts if it crashes.
*/
/*
* Copyright (c) 2016 The OpenRC Authors.
* See the Authors file at the top-level directory of this distribution and
* https://github.com/OpenRC/openrc/blob/master/AUTHORS
*
* This file is part of OpenRC. It is subject to the license terms in
* the LICENSE file found in the top-level directory of this
* distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE
* This file may not be copied, modified, propagated, or distributed
* except according to the terms contained in the LICENSE file.
*/
/* nano seconds */
#define POLL_INTERVAL 20000000
#define WAIT_PIDFILE 500000000
#define ONE_SECOND 1000000000
#define ONE_MS 1000000
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/resource.h>
#include <sys/stat.h>
#include <termios.h>
#include <sys/time.h>
#include <sys/wait.h>
#ifdef __linux__
#include <sys/syscall.h> /* For io priority */
#endif
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <limits.h>
#include <grp.h>
#include <pwd.h>
#include <signal.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <time.h>
#include <unistd.h>
#ifdef HAVE_PAM
#include <security/pam_appl.h>
/* We are not supporting authentication conversations */
static struct pam_conv conv = { NULL, NULL};
#endif
#include "einfo.h"
#include "queue.h"
#include "rc.h"
#include "rc-misc.h"
#include "_usage.h"
const char *applet = NULL;
const char *extraopts = NULL;
const char *getoptstring = "d:e:g:I:Kk:N:p:r:Su:1:2:" \
getoptstring_COMMON;
const struct option longopts[] = {
{ "chdir", 1, NULL, 'd'},
{ "env", 1, NULL, 'e'},
{ "group", 1, NULL, 'g'},
{ "ionice", 1, NULL, 'I'},
{ "stop", 0, NULL, 'K'},
{ "umask", 1, NULL, 'k'},
{ "nicelevel", 1, NULL, 'N'},
{ "pidfile", 1, NULL, 'p'},
{ "user", 1, NULL, 'u'},
{ "chroot", 1, NULL, 'r'},
{ "start", 0, NULL, 'S'},
{ "stdout", 1, NULL, '1'},
{ "stderr", 1, NULL, '2'},
longopts_COMMON
};
const char * const longopts_help[] = {
"Change the PWD",
"Set an environment string",
"Change the process group",
"Set an ionice class:data when starting",
"Stop daemon",
"Set the umask for the daemon",
"Set a nicelevel when starting",
"Match pid found in this file",
"Change the process user",
"Chroot to this directory",
"Start daemon",
"Redirect stdout to file",
"Redirect stderr to file",
longopts_help_COMMON
};
const char *usagestring = NULL;
static int nicelevel = 0;
static int ionicec = -1;
static int ioniced = 0;
static char *changeuser, *ch_root, *ch_dir;
static uid_t uid = 0;
static gid_t gid = 0;
static int devnull_fd = -1;
static int stdin_fd;
static int stdout_fd;
static int stderr_fd;
static char *redirect_stderr = NULL;
static char *redirect_stdout = NULL;
static bool exiting = false;
#ifdef TIOCNOTTY
static int tty_fd = -1;
#endif
extern char **environ;
#if !defined(SYS_ioprio_set) && defined(__NR_ioprio_set)
# define SYS_ioprio_set __NR_ioprio_set
#endif
#if !defined(__DragonFly__)
static inline int ioprio_set(int which, int who, int ioprio)
{
#ifdef SYS_ioprio_set
return syscall(SYS_ioprio_set, which, who, ioprio);
#else
return 0;
#endif
}
#endif
static void cleanup(void)
{
free(changeuser);
}
static pid_t get_pid(const char *pidfile)
{
FILE *fp;
pid_t pid;
if (! pidfile)
return -1;
if ((fp = fopen(pidfile, "r")) == NULL) {
ewarnv("%s: fopen `%s': %s", applet, pidfile, strerror(errno));
return -1;
}
if (fscanf(fp, "%d", &pid) != 1) {
ewarnv("%s: no pid found in `%s'", applet, pidfile);
fclose(fp);
return -1;
}
fclose(fp);
return pid;
}
static void child_process(char *exec, char **argv)
{
RC_STRINGLIST *env_list;
RC_STRING *env;
int i;
char *p;
char *token;
size_t len;
char *newpath;
char *np;
char **c;
char cmdline[PATH_MAX];
#ifdef HAVE_PAM
pam_handle_t *pamh = NULL;
int pamr;
const char *const *pamenv = NULL;
#endif
setsid();
if (nicelevel) {
if (setpriority(PRIO_PROCESS, getpid(), nicelevel) == -1)
eerrorx("%s: setpriority %d: %s", applet, nicelevel,
strerror(errno));
}
if (ionicec != -1 && ioprio_set(1, getpid(), ionicec | ioniced) == -1)
eerrorx("%s: ioprio_set %d %d: %s", applet, ionicec, ioniced,
strerror(errno));
if (ch_root && chroot(ch_root) < 0)
eerrorx("%s: chroot `%s': %s", applet, ch_root, strerror(errno));
if (ch_dir && chdir(ch_dir) < 0)
eerrorx("%s: chdir `%s': %s", applet, ch_dir, strerror(errno));
#ifdef HAVE_PAM
if (changeuser != NULL) {
pamr = pam_start("supervise-daemon",
changeuser, &conv, &pamh);
if (pamr == PAM_SUCCESS)
pamr = pam_acct_mgmt(pamh, PAM_SILENT);
if (pamr == PAM_SUCCESS)
pamr = pam_open_session(pamh, PAM_SILENT);
if (pamr != PAM_SUCCESS)
eerrorx("%s: pam error: %s", applet, pam_strerror(pamh, pamr));
}
#endif
if (gid && setgid(gid))
eerrorx("%s: unable to set groupid to %d", applet, gid);
if (changeuser && initgroups(changeuser, gid))
eerrorx("%s: initgroups (%s, %d)", applet, changeuser, gid);
if (uid && setuid(uid))
eerrorx ("%s: unable to set userid to %d", applet, uid);
/* Close any fd's to the passwd database */
endpwent();
#ifdef TIOCNOTTY
ioctl(tty_fd, TIOCNOTTY, 0);
close(tty_fd);
#endif
/* Clean the environment of any RC_ variables */
env_list = rc_stringlist_new();
i = 0;
while (environ[i])
rc_stringlist_add(env_list, environ[i++]);
#ifdef HAVE_PAM
if (changeuser != NULL) {
pamenv = (const char *const *)pam_getenvlist(pamh);
if (pamenv) {
while (*pamenv) {
/* Don't add strings unless they set a var */
if (strchr(*pamenv, '='))
putenv(xstrdup(*pamenv));
else
unsetenv(*pamenv);
pamenv++;
}
}
}
#endif
TAILQ_FOREACH(env, env_list, entries) {
if ((strncmp(env->value, "RC_", 3) == 0 &&
strncmp(env->value, "RC_SERVICE=", 10) != 0 &&
strncmp(env->value, "RC_SVCNAME=", 10) != 0) ||
strncmp(env->value, "SSD_NICELEVEL=", 14) == 0)
{
p = strchr(env->value, '=');
*p = '\0';
unsetenv(env->value);
continue;
}
}
rc_stringlist_free(env_list);
/* For the path, remove the rcscript bin dir from it */
if ((token = getenv("PATH"))) {
len = strlen(token);
newpath = np = xmalloc(len + 1);
while (token && *token) {
p = strchr(token, ':');
if (p) {
*p++ = '\0';
while (*p == ':')
p++;
}
if (strcmp(token, RC_LIBEXECDIR "/bin") != 0 &&
strcmp(token, RC_LIBEXECDIR "/sbin") != 0)
{
len = strlen(token);
if (np != newpath)
*np++ = ':';
memcpy(np, token, len);
np += len;
}
token = p;
}
*np = '\0';
unsetenv("PATH");
setenv("PATH", newpath, 1);
}
stdin_fd = devnull_fd;
stdout_fd = devnull_fd;
stderr_fd = devnull_fd;
if (redirect_stdout) {
if ((stdout_fd = open(redirect_stdout,
O_WRONLY | O_CREAT | O_APPEND,
S_IRUSR | S_IWUSR)) == -1)
eerrorx("%s: unable to open the logfile"
" for stdout `%s': %s",
applet, redirect_stdout, strerror(errno));
}
if (redirect_stderr) {
if ((stderr_fd = open(redirect_stderr,
O_WRONLY | O_CREAT | O_APPEND,
S_IRUSR | S_IWUSR)) == -1)
eerrorx("%s: unable to open the logfile"
" for stderr `%s': %s",
applet, redirect_stderr, strerror(errno));
}
dup2(stdin_fd, STDIN_FILENO);
if (redirect_stdout || rc_yesno(getenv("EINFO_QUIET")))
dup2(stdout_fd, STDOUT_FILENO);
if (redirect_stderr || rc_yesno(getenv("EINFO_QUIET")))
dup2(stderr_fd, STDERR_FILENO);
for (i = getdtablesize() - 1; i >= 3; --i)
close(i);
*cmdline = '\0';
c = argv;
while (*c) {
strcat(cmdline, *c);
strcat(cmdline, " ");
c++;
}
syslog(LOG_INFO, "Running command line: %s", cmdline);
execvp(exec, argv);
#ifdef HAVE_PAM
if (changeuser != NULL && pamr == PAM_SUCCESS)
pam_close_session(pamh, PAM_SILENT);
#endif
eerrorx("%s: failed to exec `%s': %s", applet, exec,strerror(errno));
}
static void handle_signal(int sig)
{
int serrno = errno;
char signame[10] = { '\0' };
switch (sig) {
case SIGINT:
snprintf(signame, sizeof(signame), "SIGINT");
break;
case SIGTERM:
snprintf(signame, sizeof(signame), "SIGTERM");
break;
case SIGQUIT:
snprintf(signame, sizeof(signame), "SIGQUIT");
break;
}
if (*signame != 0) {
syslog(LOG_INFO, "%s: caught signal %s, exiting", applet, signame);
exiting = true;
} else
syslog(LOG_INFO, "%s: caught unknown signal %d", applet, sig);
/* Restore errno */
errno = serrno;
}
static char * expand_home(const char *home, const char *path)
{
char *opath, *ppath, *p, *nh;
size_t len;
struct passwd *pw;
if (!path || *path != '~')
return xstrdup(path);
opath = ppath = xstrdup(path);
if (ppath[1] != '/' && ppath[1] != '\0') {
p = strchr(ppath + 1, '/');
if (p)
*p = '\0';
pw = getpwnam(ppath + 1);
if (pw) {
home = pw->pw_dir;
ppath = p;
if (ppath)
*ppath = '/';
} else
home = NULL;
} else
ppath++;
if (!home) {
free(opath);
return xstrdup(path);
}
if (!ppath) {
free(opath);
return xstrdup(home);
}
len = strlen(ppath) + strlen(home) + 1;
nh = xmalloc(len);
snprintf(nh, len, "%s%s", home, ppath);
free(opath);
return nh;
}
int main(int argc, char **argv)
{
int opt;
bool start = false;
bool stop = false;
char *exec = NULL;
char *pidfile = NULL;
char *home = NULL;
int tid = 0;
pid_t child_pid, pid;
char *svcname = getenv("RC_SVCNAME");
char *tmp;
char *p;
char *token;
int i;
char exec_file[PATH_MAX];
struct passwd *pw;
struct group *gr;
FILE *fp;
mode_t numask = 022;
applet = basename_c(argv[0]);
atexit(cleanup);
signal_setup(SIGINT, handle_signal);
signal_setup(SIGQUIT, handle_signal);
signal_setup(SIGTERM, handle_signal);
openlog(applet, LOG_PID, LOG_DAEMON);
if ((tmp = getenv("SSD_NICELEVEL")))
if (sscanf(tmp, "%d", &nicelevel) != 1)
eerror("%s: invalid nice level `%s' (SSD_NICELEVEL)",
applet, tmp);
/* Get our user name and initial dir */
p = getenv("USER");
home = getenv("HOME");
if (home == NULL || p == NULL) {
pw = getpwuid(getuid());
if (pw != NULL) {
if (p == NULL)
setenv("USER", pw->pw_name, 1);
if (home == NULL) {
setenv("HOME", pw->pw_dir, 1);
home = pw->pw_dir;
}
}
}
while ((opt = getopt_long(argc, argv, getoptstring, longopts,
(int *) 0)) != -1)
switch (opt) {
case 'I': /* --ionice */
if (sscanf(optarg, "%d:%d", &ionicec, &ioniced) == 0)
eerrorx("%s: invalid ionice `%s'",
applet, optarg);
if (ionicec == 0)
ioniced = 0;
else if (ionicec == 3)
ioniced = 7;
ionicec <<= 13; /* class shift */
break;
case 'K': /* --stop */
stop = true;
break;
case 'N': /* --nice */
if (sscanf(optarg, "%d", &nicelevel) != 1)
eerrorx("%s: invalid nice level `%s'",
applet, optarg);
break;
case 'S': /* --start */
start = true;
break;
case 'd': /* --chdir /new/dir */
ch_dir = optarg;
break;
case 'e': /* --env */
putenv(optarg);
break;
case 'g': /* --group <group>|<gid> */
if (sscanf(optarg, "%d", &tid) != 1)
gr = getgrnam(optarg);
else
gr = getgrgid((gid_t)tid);
if (gr == NULL)
eerrorx("%s: group `%s' not found",
applet, optarg);
gid = gr->gr_gid;
break;
case 'k':
if (parse_mode(&numask, optarg))
eerrorx("%s: invalid mode `%s'",
applet, optarg);
break;
case 'p': /* --pidfile <pid-file> */
pidfile = optarg;
break;
case 'r': /* --chroot /new/root */
ch_root = optarg;
break;
case 'u': /* --user <username>|<uid> */
{
p = optarg;
tmp = strsep(&p, ":");
changeuser = xstrdup(tmp);
if (sscanf(tmp, "%d", &tid) != 1)
pw = getpwnam(tmp);
else
pw = getpwuid((uid_t)tid);
if (pw == NULL)
eerrorx("%s: user `%s' not found",
applet, tmp);
uid = pw->pw_uid;
home = pw->pw_dir;
unsetenv("HOME");
if (pw->pw_dir)
setenv("HOME", pw->pw_dir, 1);
unsetenv("USER");
if (pw->pw_name)
setenv("USER", pw->pw_name, 1);
if (gid == 0)
gid = pw->pw_gid;
if (p) {
tmp = strsep (&p, ":");
if (sscanf(tmp, "%d", &tid) != 1)
gr = getgrnam(tmp);
else
gr = getgrgid((gid_t) tid);
if (gr == NULL)
eerrorx("%s: group `%s'"
" not found",
applet, tmp);
gid = gr->gr_gid;
}
}
break;
case '1': /* --stdout /path/to/stdout.lgfile */
redirect_stdout = optarg;
break;
case '2': /* --stderr /path/to/stderr.logfile */
redirect_stderr = optarg;
break;
case_RC_COMMON_GETOPT
}
if (!pidfile)
eerrorx("%s: --pidfile must be specified", applet);
endpwent();
argc -= optind;
argv += optind;
exec = *argv;
if (start) {
if (!exec)
eerrorx("%s: nothing to start", applet);
}
/* Expand ~ */
if (ch_dir && *ch_dir == '~')
ch_dir = expand_home(home, ch_dir);
if (ch_root && *ch_root == '~')
ch_root = expand_home(home, ch_root);
if (exec) {
if (*exec == '~')
exec = expand_home(home, exec);
/* Validate that the binary exists if we are starting */
if (*exec == '/' || *exec == '.') {
/* Full or relative path */
if (ch_root)
snprintf(exec_file, sizeof(exec_file),
"%s/%s", ch_root, exec);
else
snprintf(exec_file, sizeof(exec_file),
"%s", exec);
} else {
/* Something in $PATH */
p = tmp = xstrdup(getenv("PATH"));
*exec_file = '\0';
while ((token = strsep(&p, ":"))) {
if (ch_root)
snprintf(exec_file, sizeof(exec_file),
"%s/%s/%s",
ch_root, token, exec);
else
snprintf(exec_file, sizeof(exec_file),
"%s/%s", token, exec);
if (exists(exec_file))
break;
*exec_file = '\0';
}
free(tmp);
}
}
if (start && !exists(exec_file))
eerrorx("%s: %s does not exist", applet,
*exec_file ? exec_file : exec);
if (stop) {
pid = get_pid(pidfile);
if (pid == -1)
i = pid;
else
i = kill(pid, SIGTERM);
if (i != 0)
/* We failed to stop something */
exit(EXIT_FAILURE);
/* Even if we have not actually killed anything, we should
* remove information about it as it may have unexpectedly
* crashed out. We should also return success as the end
* result would be the same. */
if (pidfile && exists(pidfile))
unlink(pidfile);
if (svcname)
rc_service_daemon_set(svcname, exec,
(const char *const *)argv,
pidfile, false);
exit(EXIT_SUCCESS);
}
pid = get_pid(pidfile);
if (pid != -1)
if (kill(pid, 0) == 0)
eerrorx("%s: %s is already running", applet, exec);
einfov("Detaching to start `%s'", exec);
eindentv();
/* Remove existing pidfile */
if (pidfile)
unlink(pidfile);
/*
* Make sure we can write a pid file
*/
fp = fopen(pidfile, "w");
if (! fp)
eerrorx("%s: fopen `%s': %s", applet, pidfile, strerror(errno));
fclose(fp);
child_pid = fork();
if (child_pid == -1)
eerrorx("%s: fork: %s", applet, strerror(errno));
/* first parent process, do nothing. */
if (child_pid != 0)
exit(EXIT_SUCCESS);
child_pid = fork();
if (child_pid == -1)
eerrorx("%s: fork: %s", applet, strerror(errno));
if (child_pid != 0) {
/* this is the supervisor */
umask(numask);
#ifdef TIOCNOTTY
tty_fd = open("/dev/tty", O_RDWR);
#endif
devnull_fd = open("/dev/null", O_RDWR);
fp = fopen(pidfile, "w");
if (! fp)
eerrorx("%s: fopen `%s': %s", applet, pidfile, strerror(errno));
fprintf(fp, "%d\n", getpid());
fclose(fp);
/*
* Supervisor main loop
*/
i = 0;
while (!exiting) {
wait(&i);
if (exiting) {
syslog(LOG_INFO, "stopping %s, pid %d", exec, child_pid);
kill(child_pid, SIGTERM);
} else {
if (WIFEXITED(i))
syslog(LOG_INFO, "%s, pid %d, exited with return code %d",
exec, child_pid, WEXITSTATUS(i));
else if (WIFSIGNALED(i))
syslog(LOG_INFO, "%s, pid %d, terminated by signal %d",
exec, child_pid, WTERMSIG(i));
child_pid = fork();
if (child_pid == -1)
eerrorx("%s: fork: %s", applet, strerror(errno));
if (child_pid == 0)
child_process(exec, argv);
}
}
if (svcname)
rc_service_daemon_set(svcname, exec,
(const char * const *) argv, pidfile, true);
exit(EXIT_SUCCESS);
} else if (child_pid == 0)
child_process(exec, argv);
}

View File

@@ -0,0 +1,6 @@
#%PAM-1.0
auth required pam_permit.so
account required pam_permit.so
password required pam_deny.so
session optional pam_limits.so

49
supervise-daemon-guide.md Normal file
View File

@@ -0,0 +1,49 @@
# Using supervise-daemon
Beginning with OpenRC-0.21 we have our own daemon supervisor,
supervise-daemon., which can start a daemon and restart it if it
terminates unexpectedly.
The following is a brief guide on using this capability.
## Use Default start, stop and status functions
If you write your own start, stop and status functions in your service
script, none of this will work. You must allow OpenRC to use the default
functions.
## Daemons must not fork
Any deamon that you would like to have monitored by supervise-daemon
must not fork. Instead, it must stay in the foreground. If the daemon
itself forks, the supervisor will be unable to monitor it.
If the daemon can be configured to not fork, this should be done in the
daemon's configuration file, or by adding a command line option that
instructs it not to fork to the command_args_foreground variable shown
below.
## Variable Settings
The most important setting is the supervisor variable. At the top of
your service script, you should set this variable as follows:
supervisor=supervise-daemon
Several other variables affect the way services behave under
supervise-daemon. They are documented on the openrc-run man page, but I
will list them here for convenience:
pidfile=/pid/of/supervisor.pid
If you are using start-stop-daemon to monitor your scripts, the pidfile
is the path to the pidfile the daemon creates. If, on the other hand,
you are using supervise-daemon, this is the path to the pidfile the
supervisor creates.
command_args_foreground should be used if the daemon you want to monitor
forks and goes to the background by default. This should be set to the
command line option that instructs the daemon to stay in the foreground.
This is very early support, so feel free to file bugs if you have
issues.