Compare commits

..

58 Commits

Author SHA1 Message Date
18d9f0c807 config rc_libexecdir 2024-04-30 20:21:56 +02:00
John Einar Reitan
3d30b6fdda Add xterm-kitty to color capable term list 2024-04-05 00:02:33 -05:00
William Hubbs
4574b5d8e4 clarify news update about split-usr option 2024-04-01 14:22:37 -05:00
William Hubbs
6b42019697 version 0.54 2024-04-01 12:06:53 -05:00
William Hubbs
42408e7488 update news 2024-04-01 12:05:18 -05:00
Oskari Pirhonen
957140cb78 Touch up docs/comments
Remove the mention of linking with libtermcap from einfo(3), and fix
some comments in libeinfo.c to more accurately reflect the new
situation.
2024-03-31 23:13:02 -05:00
Oskari Pirhonen
536794dfad Trivial curses/termcap removal
Remove the curses code and make the HAVE_TERMCAP-gated "fallbacks"
always present. This makes an ANSI terminal required for colors.

X-Gentoo-Bug: https://bugs.gentoo.org/904277
Closes: https://github.com/OpenRC/openrc/issues/619
2024-03-31 23:13:02 -05:00
William Hubbs
7ac2080e31 ci: update FreeBSD releases we test against 2024-03-31 18:31:19 -05:00
Sam James
12e1e88475 meson: drop broken split-usr handling
Two issues here:

* The 'split-usr' meson option wasn't doing anything, it tried to check
  if /bin was a symlink, but nothing acted on this information.

* The actual rootprefix default was decided based on whether /bin was a symlink
  which is flaky if e.g. building on a merged-usr system for use on a non-merged-usr
  system.

People can set -Drootprefix=/usr if they wish.

There's no real advantage to installing to /usr over / as the compat. symlinks
are really here to stay. If someone really does care about this, they can bring
it back and do it properly, but it doesn't seem worth it to me at all.

Bug: https://bugs.gentoo.org/927776
Fixes: cc0037e9ca
Fixes: f2362cc277
Fixes: #696
2024-03-25 14:10:13 -05:00
William Hubbs
c45fe9fba5 version 0.53 2024-01-12 11:29:03 -06:00
William Hubbs
961c479e1d update news 2024-01-12 11:24:48 -06:00
Forza-tng
f9c92d7822 enable confd cgroups mount options
This fixes #684.
2024-01-12 11:17:14 -06:00
Natanael Copa
97689d6c44 sh/rc-cgroup.sh: add openrc. prefix the cgroupv2 path
Some services, like docker, creates and manages /sys/fs/cgroup/<service>
themselves. Avoid conflict with the openrc created cgroup path by adding
a `openrc.` prefix.

Fixes: https://github.com/OpenRC/openrc/issues/680
2024-01-09 10:09:59 -06:00
Alexey Vazhnov
439cce426d supervise-daemon-guide.md: adjust markdown formatting. No logic/text changes were made. 2023-12-16 09:10:18 -05:00
Zhao Yongming
bfdafe4463 change info words "remove" to "delete" in delete sub-command
This close #664
2023-12-04 10:53:23 -05:00
Zhao Yongming
179ff285ca update start-stop-daemon manual to include --quiet 2023-12-04 10:52:07 -05:00
William Hubbs
f9bbbfbf4b update news 2023-11-16 23:29:09 -06:00
William Hubbs
59a175541d remove warning for runscript deprecation 2023-11-15 10:04:46 -06:00
William Hubbs
65b13eb86f drop the deprecated "rc" binary
This binary is a copy of the openrc binary. Referring to it as rc was
deprecated in 2016, so we should be able to drop it at this point.
2023-11-15 10:01:45 -06:00
Alexander Maltsev
fda9dcd1f2 Skip already processed files in rc_service_daemon_set
Fixes the problem described in https://bugs.gentoo.org/916947 -
start-stop-daemon hangs in infinite loop when stopping some daemons on
linux 6.6+

It appears linux 6.6 reworked tmpfs, and since then it triggers this
problem in openrc: when iterating over files via readdir, running rename
on a file could result in reading the same file again with next readdir
call.

The Open Group manual for readdir explicitly states "If a file is
removed from or added to the directory after the most recent call to
opendir() or rewinddir(), whether a subsequent call to readdir() returns
an entry for that file is unspecified.". Linux man page don't seem to
mention that, but don't seem to say anything to contradict that either.
So I presume we can't rely on some specific behaviour here.

Bug: https://bugs.gentoo.org/916947
2023-11-14 14:35:23 -06:00
Sam James
6f180e9424 init.d/cgroups.in: fix inconsistency between mount_cgroups and mount_cgroups
965de92b37 changed the default cgroup mode which
exposes an issue in init.d/cgroups.in.

While mount_cgroups defaults to 'unified' if rc_cgroup_mode is unset, cgroup2_controllers
has no default and therefore has a mismatch with the logic in mount_cgroups. The
two should be consistent so the flow makes sense, as mount_cgroups expects a certain
path to be taken in cgroup2_controllers.

Make cgroup2_controllers default to 'unified' if rc_cgroup_mode is unset, just
like mount_cgroups.

Bug: https://bugs.gentoo.org/916964
Thanks-to: acab@digitalfuture.it
2023-11-14 14:31:22 -06:00
William Hubbs
88e5d98d05 drop the deprecated runscript binary 2023-11-14 14:19:35 -06:00
Haelwenn (lanodan) Monnier
1433552435 sh/supervise-daemon.sh: Proper casing for --no-new-privs 2023-11-02 13:35:37 -04:00
William Hubbs
554ccab718 version 0.51 2023-10-10 14:16:44 -05:00
William Hubbs
228b3c6c99 update news 2023-10-10 14:15:15 -05:00
William Hubbs
965de92b37 change default RC_CGROUP_MODE to unified
This improves resource management by assigning services to individual
cgroups.

X-Gentoo-Bug: https://bugs.gentoo.org/914972
2023-10-10 12:50:09 -05:00
Adam Duskett
b85d771e1f Force symlinking of openrc-init to init
When building on embedded SDKs such as Buildroot or Yocto, if OpenRC has a
previous installation, the package will fail the installation step as the
openrc-init is already a symlink to "${DESTDIR}/${sbindir}"/init. Force
symlinking to prevent errors when reinstalling the package.
2023-10-10 08:55:33 -04:00
Lexxy Fox
cf9286d2d8 Relocate pipes.c and pipes.h file to shared directory.
With the addition of logger process redirect in supervise-daemon,
pipes.c and pipes.h are now included in both s-s-d and supervise-daemon.
Thus it makes sense to move the source files to the src/shared dir.
2023-10-03 16:43:39 -05:00
Lexxy Fox
9934e9f96e supervise-daemon: implement output_logger and error_logger.
Allows redirecting process stdin and stdout to another process,
just like is already possible with start-stop-daemon.

Also added --stdout-logger and --stderr-logger to the man page.
2023-10-03 16:43:39 -05:00
William Hubbs
f1e5510ccf version 0.50 2023-09-19 16:02:03 -05:00
William Hubbs
1b72c3a7ab update news 2023-09-19 15:59:31 -05:00
Natanael Copa
c4785f1b99 misc: add syscall fallback for close_range for musl libc
Add fallback for the close_range syscall wrapper. This is needed for
musl libc, which currently does not have a close_range wrapper.

Also set errno on errors.
2023-09-12 22:53:12 -05:00
Natanael Copa
e447562aaa start-stop-daemon: set fds to CLOEXEC instead of closing
Set file descriptors to CLOEXEC instead of closing them before exec,
similar to what we do in supervise-daemon.

Use the share cloexec_fds_from() helper for this.

closefrom() is no longer used so remove the test.
2023-09-12 22:53:12 -05:00
Natanael Copa
c199c5cf6e misc: add cloexec_fds_from() helper function
Move logic to set file descriptors to a cloexec_fds_from() function in
misc.c so it can be shared by both supervisor-daemon and
start-stop-daemon, and hide the details behind.
2023-09-12 22:53:12 -05:00
Natanael Copa
5bfb592d75 supervise-daemon: rename HAVE_CLOSE_RANGE_EXEC to HAVE_CLOSE_RANGE
Use HAVE_CLOSE_RANGE to tell if system provides a close_range(2)
wrapper, which better explains the purpose.

Add a compat inline which returns -1 if close_range is unavailable.
2023-09-12 22:53:12 -05:00
Timothy Kenno Handojo
b2c4eb97b5 remove /lib/rc/tmp creation from meson script
It is apparently for a piece of code that no longer exist.
There don't seem to be any part of the code referring to this directory (anymore, if there was).
2023-09-01 11:54:30 -05:00
William Hubbs
e740913fcb version 0.49 2023-08-31 14:13:19 -05:00
William Hubbs
1bc34a39cd update news 2023-08-31 14:12:26 -05:00
Sam James
c1cd3c9830 Don't re-define strlcpy/strlcat with >=glibc-2.38
`>=glibc-2.38` implements strlcpy, strlcat, etc so check for those functions
with Meson and don't provide conflicting prototypes.

Technically, it doesn't need _GNU_SOURCE, but it's easier because it's not
clear right now what glibc wants to guard it with. Note that these are in
POSIX next anyway.

Fixes: https://github.com/OpenRC/openrc/issues/643
Signed-off-by: Sam James <sam@gentoo.org>
2023-08-29 23:31:18 -04:00
Sven Wegener
86efc43d0e rc: fix automatic restart with runlevel-specific conf.d files
Commit fc4f15d6cd broke the automatic restart of
services having runlevel-specific conf.d files.

The double dirname() was not a mistake, but the way of getting from the
service script in init.d to the upper directory containing the conf.d
directory. dirname() modifies the argument in-place, so the second call
operated on a modified value. To make it more obvious what is going on,
have the second call operate on the returned value from the first call.

Fixes: fc4f15d ("openrc: fix double-assignment to dir")
Signed-off-by: Sven Wegener <sven.wegener@stealer.net>
2023-07-26 22:41:42 -05:00
Jernej Jakob
cd53239701 bash-completion/rc-service: don't set or unset extglob
It breaks bash-completion.
It's not necessary to set extglob as patterns in '[[' after '=='
are always matched as if extglob were set.

Closes: #636
Signed-off-by: Jernej Jakob <jernej.jakob@gmail.com>
2023-07-26 22:41:19 -05:00
William Hubbs
92662ddc44 version 0.48 2023-07-05 16:28:44 -05:00
William Hubbs
1b6a35488d update news for 0.48 release 2023-07-05 16:25:28 -05:00
Petr Vaněk
1eccb7f5e6 man: Remove Duplicate Description of -2/--stderr Flag
This commit removes the secondary mention of the -2/--stderr flag in the
start-stop-daemon man page. The flag's functionality was already
sufficiently described in an earlier section of the text.

Signed-off-by: Petr Vaněk <arkamar@atlas.cz>
2023-05-21 10:57:53 -04:00
Oskari Pirhonen
fe37fc9322 einfo: fix vewend applet args
Fix typo preventing the args for the vewend applet from being handled.
2023-05-14 00:50:03 -04:00
Sam James
edf5f830e3 librc: allow overriding rc_interactive on kernel command line
This was originally introduced in 14625346c0 with
an example list (just one for rc_parallel) of options. Let's add in rc_interactive
as it's a pretty obvious thing one might want to override.

See https://forums.gentoo.org/viewtopic-p-8694588.html.
2023-05-10 21:39:25 -04:00
Dominique Martinet
863e1a5c87 openrc-run: fix rc_parallel race in svc_exec
svc_exec waits until SIGCHLD comes in to close its input, but in
rc_parallel case the SIGCHLD might be unrelated.

Checking the proper pid is found in signal handler and only signaling
signal_pipe the status code directly avoids this problem.
2023-04-24 22:06:53 -05:00
Dominique Martinet
0b9c3c0803 openrc-run: silence lock failures with --no-deps
work around scary warnings described in previous commit
2023-04-24 22:06:41 -05:00
Dominique Martinet
a3c721b682 openrc-run: remove kludge in restart --no-deps
restarting a service with --no-deps ran into a "hairy workaround", which
had a few problems discussed in [1]:
 - it ignores --dry-run, really restarting the requested service
 - if the service was stopped, the program is started but the service
status stays stopped. This makes long-lived services impossible to
(re)start again (pid already exists and running), and the service also
won't stop on shutdown.

The kludge had a long comment describing the following situation:
 - openvpn needs net and dns
 - net restarts dns
 - dns needs net

If the restart in net handled deps, openrc would deadlock waiting for
net in dns' restart, as net won't be started until that is done.

Restarting with --nodeps works around the deadlock, but can display
errors without the kludge (note that the services did start properly
anyway, the problem is that the default service path tries to lock dns
twice from openvn's dep's start and net's start's restart):
---
alpine:~# rc-service openvn start
openvn                   | * Caching service dependencies ...                                                                                                      [ ok ]
net                      |net starting
net                      |dns                       | * Call to flock failed: Resource temporarily unavailable
net                      |dns                       | * ERROR: dns stopped by something else
net                      |net started
dns                      |dns started
openvn                   |openvn started
alpine:~# rc-status | grep s[1-3]
 net                                                               [  started  ]
 dns                                                               [  started  ]
 openvn                                                            [  started  ]
---

Locking again in restart --nodep can fail in two patterns:
 - openvpn's need dependency start was first, and the restart in net
failed (case above): we can just silence locking failures and exit quietly
with restart --no-deps, which is not worse than trying to restart while
another process hold the lock.
 - the restart in net's start was first, and openvpn's need dependency
start failed: not much can be done here short of adding a new status
that a no-deps restart is in progress as in the comment, but this case
can actually just be solved by adjusting dependencies -- and it actually
has already been fixed: the current openvpn init script in alpine only
'use dns', so it will not try to start it, and that will start just
fine with openvpn -> net -> dns only each starting each other once
sequentially.

Another failure pattern is just starting dns directly: that will start
net, which will try to restart dns while we are starting it.
Silencing messages on restart also solves this.

Link: https://github.com/OpenRC/openrc/issues/224 [1]
2023-04-24 22:06:41 -05:00
NRK
3f82d5b1a3 rc: use LIST_FOREACH_SAFE in cleanup()
according to the linux manpage, the "safe" variant may not be available
on all platform. however we bundle our own `queue.h` so this should not
be an issue.
2023-04-24 19:20:19 -05:00
NRK
0b4732520f rc: block SIGCHLD during pid list operations
the pid list will be accessed inside the SIGCHLD signal handler. so we
must ensure SIGCHLD handler doesn't get invoked while the list is at an
inconsistent state making it unsafe to interact with.

Co-authored-by: Dominique MARTINET <dominique.martinet@atmark-techno.com>
Bug: https://github.com/OpenRC/openrc/issues/589#issuecomment-1406588576
2023-04-24 19:20:19 -05:00
NRK
bbd3acfc67 rc: avoid calling free inside SIGCHLD handler
`free` is not async-signal-safe and calling it inside a signal handler
can have bad effects, as reported in the musl ML:
https://www.openwall.com/lists/musl/2023/01/23/1

the solution:

- keep track of weather remove_pid() is being called from inside a
  signal handler or not.
- if it's inside a signal handler then DO NOT call free - instead put
  that pointer into a "to be freed later" list.
- if it's not inside a signal handler then take the "to be freed later"
  list and free anything in it.

Bug: https://github.com/OpenRC/openrc/issues/589
Reported-by: Dominique MARTINET <dominique.martinet@atmark-techno.com>
2023-04-24 19:20:19 -05:00
NRK
910e3e2a0e fstabinfo: deal with EINTR in waitpid call 2023-04-24 19:18:18 -05:00
NRK
5f04dcc951 fstabinfo: replace vfork with posix_spawnp
problem:
* vfork has been removed from POSIX [0].
* clang-tidy flags the `strerror` and `eerror` call inside the vfork-ed
  child as undefined behavior.

solution: use posix_spawnp, which is serves similar purpose and is
specified in posix. and as an added bonus, it's also easier to use and
less lines of code.

[0]: https://www.man7.org/linux/man-pages/man2/vfork.2.html#CONFORMING_TO
2023-04-24 19:18:18 -05:00
Oskari Pirhonen
8f52c64c37 einfo.h: fix EINFO_RESTRICT macro usage
Make function declarations use the EINFO_RESTRICT macro instead of
__EINFO_RESTRICT which gets treated as the name of the argument.
2023-04-23 16:11:15 -04:00
Sam James
09d405fb3e shared: fix pointer type in UNCONST
Thanks to vapier for noticing.
2023-04-20 07:50:49 -04:00
Sam James
36e4e04ba9 meson.build: add -Werror=... for modern C issues
Clang 16 makes these warnings fatal and GCC 14 is likely to as well.
2023-04-19 16:44:51 -04:00
Sam James
eb8831a141 Rename attribute macros to namespaced RC_*
This conflicts with linux-headers which uses __unused for some padding members
on ppc64le at least.

Closes: https://github.com/OpenRC/openrc/issues/622
2023-04-19 16:44:51 -04:00
37 changed files with 360 additions and 308 deletions

View File

@@ -4,8 +4,8 @@
test_task:
freebsd_instance:
matrix:
image: freebsd-13-1-release-amd64
image: freebsd-12-4-release-amd64
image: freebsd-13-2-release-amd64
image: freebsd-13-3-release-amd64
env:
OS: FreeBSD
procfs_script: >

52
NEWS.md
View File

@@ -4,6 +4,58 @@ OpenRC NEWS
This file will contain a list of notable changes for each release. Note
the information in this file is in reverse order.
## OpenRC 0.54
This release drops the support for the split-usr build option.
Also, it drops the support for ncurses/termcap and uses ansi codes
directly for color support on terminals that support them.
## OpenRC 0.53
The names of cgroups for services started by OpenRC are now prefixed by
"openrc." This is done because some services, like docker, create their
own cgroups.
It is now possible to override the mount options used to mount the
cgroups filesystems.
## OpenRC 0.52
This release drops the "runscript" and "rc" binaries.
These binaries have been deprecated for multiple years, so it should be
fine to remove them at this point.
There was an issue before this release with the default setting for
cgroups being inconsistent. This is fixed.
Start-stop-daemon did not work correctly on Linux 6.6 systems.
This has been fixed in this release as well.
## OpenRC 0.51
The default RC_CGROUP_MODE has been updated to unified.
This benefits users since it will assign each service to its own cgroup,
making resource nanagement better over all.
OUTPUT_LOGGER and ERROR_LOGGER have been implemented for
supervise-daemon. For mor einformation on these settings, please check
the man page.
## OpenRC 0.50
This is a bug fix release which fixes a significant performance issue on
musl libc systems.
## OpenRC 0.49
This release adds support for glibc's builtin
strlcpy, strlcat etc functions, which will be in posix next.
Also, it fixes completions.
## OpenRC 0.48
This release is a maintenance release; it has no user-facing changes.
## OpenRC 0.47
This release is primarily an internal cleanup release.

View File

@@ -92,13 +92,11 @@ _rc_service()
return 0
elif [[ ${COMP_CWORD} -eq 2 ]] && [[ ${prev} != -* ]]; then # if second word typed and we didn't type in a function
rc-service --exists "$prev" || return
shopt -s extglob
while read -r _ line; do
if [[ $line == +([[:alnum:]_]):* ]]; then
opts+="${line%%:*} "
fi
done < <(rc-service "$prev" describe 2>&1)
shopt -u extglob
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
return 0
fi

2
conf.d/cgroups Normal file
View File

@@ -0,0 +1,2 @@
# override cgroup mount options
#cgroup_opts=nodev,noexec,nosuid

View File

@@ -199,7 +199,7 @@ rc_tty_number=12
# cgroups version 1 on /sys/fs/cgroup.
# "legacy" mounts cgroups version 1 on /sys/fs/cgroup
# "unified" mounts cgroups version 2 on /sys/fs/cgroup
#rc_cgroup_mode="hybrid"
#rc_cgroup_mode="unified"
# This is a list of controllers which should be enabled for cgroups version 2
# when hybrid mode is being used.

View File

@@ -11,7 +11,7 @@
description="Mount the control groups."
cgroup_opts=nodev,noexec,nosuid
: "${cgroup_opts:="nodev,noexec,nosuid"}"
depend()
{
@@ -87,7 +87,7 @@ cgroup2_controllers()
[ ! -e "${cgroup_path}/cgroup.subtree_control" ]&& return 0
read -r active < "${cgroup_path}/cgroup.controllers"
for x in ${active}; do
case "$rc_cgroup_mode" in
case "${rc_cgroup_mode:-unified}" in
unified)
echo "+${x}" > "${cgroup_path}/cgroup.subtree_control"
;;
@@ -128,7 +128,7 @@ cgroups_unified()
mount_cgroups()
{
case "${rc_cgroup_mode:-hybrid}" in
case "${rc_cgroup_mode:-unified}" in
hybrid) cgroups_hybrid ;;
legacy) cgroups_legacy ;;
unified) cgroups_unified ;;

View File

@@ -158,13 +158,6 @@ is true.
prefixes the string
.Fa prefix
to the above functions.
.Sh IMPLEMENTATION NOTES
einfo can optionally be linked against the
.Lb libtermcap
so that we can correctly query the connected console for our color and
cursor escape codes.
If not, then we have a hard coded list of terminals we know about that support
the commonly used codes for color and cursor position.
.Sh ENVIRONMENT
.Va EINFO_QUIET
when set to true makes the

View File

@@ -84,6 +84,8 @@ Print the action(s) that would be taken, but don't actually do anything.
The return value is set as if the command was taken and worked.
.It Fl v , -verbose
Print the action(s) that are taken just before doing them.
.It Fl q , -quiet
Run quietly (repeat to suppress errors).
.It Fl P , -progress
Echo a . to the console for each second elapsed whilst waiting.
.El
@@ -183,10 +185,6 @@ Wait
after starting and check that daemon is still running.
Useful for daemons that check configuration after forking or stopping race
conditions where the pidfile is written out after forking.
.It Fl 2 , -stderr Ar logfile
The same thing as
.Fl 1 , -stdout
but with the standard error output.
.El
.Pp
These options are only used for stopping daemons:

View File

@@ -158,6 +158,23 @@ The logfile can also be a named pipe.
The same thing as
.Fl 1 , -stdout
but with the standard error output.
.It Fl -stdout-logger Ar cmd
Run cmd as a child process redirecting the standard output to the
standard input of cmd when started with
.Fl background .
Cmd must be an absolute pathname, but relative to the path optionally given with
.Fl r , -chroot .
This process must be prepared to accept input on stdin and be able to
log it or send it to another location.
.It Fl -stderr-logger Ar cmd
Run cmd as a child process and
Redirect the standard error of the process to the standard input of cmd
when started with
.Fl background .
Cmd must be an absolute pathname, but relative to the path optionally given with
.Fl r , -chroot .
This process must be prepared to accept input on stdin and be able to
log it or send it to another location.
.It Fl -capabilities Ar cap-list
Start the daemon with the listed inheritable, ambient and bounding capabilities.
The format is the same as in cap_iab(3).

View File

@@ -1,5 +1,5 @@
project('OpenRC', 'c',
version : '0.47.1',
version : '0.54',
license: 'BSD-2',
default_options : [
'c_std=c99',
@@ -83,16 +83,9 @@ else
pkg_prefix = option_pkg_prefix
endif
if get_option('split-usr') == 'auto'
split_usr = run_command('test', '-L', '/bin', check: false).returncode() != 0
else
split_usr = get_option('split-usr') == 'true'
endif
rootprefix = get_option('rootprefix')
rootprefix_default = fs.is_symlink('/bin') ? '/usr' : '/'
if rootprefix == ''
rootprefix = rootprefix_default
rootprefix = '/'
endif
bindir = rootprefix / get_option('bindir')
@@ -102,7 +95,7 @@ if os == 'Linux' and libexecdir == 'libexec'
libexecdir = 'lib'
endif
libexecdir = rootprefix / libexecdir
rc_libexecdir = libexecdir / 'rc'
rc_libexecdir = libexecdir / get_option('librcdir')
rc_bindir = rc_libexecdir / 'bin'
rc_sbindir = rc_libexecdir / 'sbin'
rc_shdir = rc_libexecdir / 'sh'
@@ -133,15 +126,6 @@ else
cc_selinux_flags = []
endif
termcap = get_option('termcap')
if termcap != ''
termcap_dep = dependency(termcap)
termcap_flags = '-DHAVE_TERMCAP'
else
termcap_dep = []
termcap_flags = []
endif
if get_option('buildtype').startswith('debug')
cc_debug_flags = ['-DRC_DEBUG']
else
@@ -176,7 +160,10 @@ cc_warning_flags_test = [
'-Wsequence-point',
'-Wshadow',
'-Wwrite-strings',
'-Werror=implicit-int',
'-Werror=implicit-function-declaration',
'-Werror=int-conversion',
'-Werror=incompatible-function-pointer-types',
]
cc_warning_flags = cc.get_supported_arguments(cc_warning_flags_test)
cc_flags = [cc_debug_flags, cc_os_flags, cc_warning_flags]
@@ -192,12 +179,14 @@ if cc.compiles(malloc_attribute_test, name : 'malloc attribute with arguments')
add_project_arguments('-DHAVE_MALLOC_EXTENDED_ATTRIBUTE', language: 'c')
endif
if cc.has_function('closefrom', prefix: '#define _GNU_SOURCE\n#include <unistd.h>')
add_project_arguments('-DHAVE_CLOSEFROM', language: 'c')
if cc.has_function('close_range', prefix: '#define _GNU_SOURCE\n#include <unistd.h>')
add_project_arguments('-DHAVE_CLOSE_RANGE', language: 'c')
elif cc.has_header('linux/close_range.h')
add_project_arguments('-DHAVE_LINUX_CLOSE_RANGE_H', language: 'c')
endif
if cc.has_function('close_range', prefix: '#define _GNU_SOURCE\n#include <unistd.h>') and \
cc.has_header_symbol('unistd.h', 'CLOSE_RANGE_CLOEXEC', prefix: '#define _GNU_SOURCE')
add_project_arguments('-DHAVE_CLOSE_RANGE_CLOEXEC', language: 'c')
if cc.has_function('strlcpy', prefix: '#define _GNU_SOURCE\n#include <string.h>')
add_project_arguments('-DHAVE_STRLCPY', language: 'c')
endif
incdir = include_directories('src/shared')

View File

@@ -26,14 +26,9 @@ option('selinux', type : 'feature', value : 'auto',
description : 'enable SELinux support')
option('shell', type : 'string', value : '/bin/sh',
description : 'Default posix compatible shell')
option('split-usr', type : 'combo',
choices : ['auto', 'true', 'false'],
description : '''/bin, /sbin aren't symlinks into /usr''')
option('sysvinit', type : 'boolean', value : false,
description : 'enable SysVinit compatibility (linux only)')
option('termcap', type : 'combo',
choices :
[ '', 'ncurses', 'termcap' ],
description : 'the termcap library to use')
option('zsh-completions', type : 'boolean',
description : 'install zsh completions')
option('librcdir', type : 'string', value : 'rc',
description : 'default location of rc libexec dir')

View File

@@ -35,7 +35,7 @@ cgroup_get_pids()
cgroup_pids=
cgroup_procs="$(cgroup2_find_path)"
if [ -n "${cgroup_procs}" ]; then
cgroup_procs="${cgroup_procs}/${RC_SVCNAME}/cgroup.procs"
cgroup_procs="${cgroup_procs}/openrc.${RC_SVCNAME}/cgroup.procs"
else
cgroup_procs="/sys/fs/cgroup/openrc/${RC_SVCNAME}/tasks"
fi
@@ -154,7 +154,7 @@ cgroup_set_limits()
cgroup2_find_path()
{
if grep -qw cgroup2 /proc/filesystems; then
case "${rc_cgroup_mode:-hybrid}" in
case "${rc_cgroup_mode:-unified}" in
hybrid) printf "/sys/fs/cgroup/unified" ;;
unified) printf "/sys/fs/cgroup" ;;
esac
@@ -167,7 +167,7 @@ cgroup2_remove()
local cgroup_path rc_cgroup_path
cgroup_path="$(cgroup2_find_path)"
[ -z "${cgroup_path}" ] && return 0
rc_cgroup_path="${cgroup_path}/${RC_SVCNAME}"
rc_cgroup_path="${cgroup_path}/openrc.${RC_SVCNAME}"
[ ! -d "${rc_cgroup_path}" ] ||
[ ! -e "${rc_cgroup_path}"/cgroup.events ] &&
return 0
@@ -191,7 +191,7 @@ cgroup2_set_limits()
cgroup_path="$(cgroup2_find_path)"
[ -z "${cgroup_path}" ] && return 0
mountinfo -q "${cgroup_path}"|| return 0
rc_cgroup_path="${cgroup_path}/${RC_SVCNAME}"
rc_cgroup_path="${cgroup_path}/openrc.${RC_SVCNAME}"
[ ! -d "${rc_cgroup_path}" ] && mkdir "${rc_cgroup_path}"
[ -f "${rc_cgroup_path}"/cgroup.procs ] &&
printf 0 > "${rc_cgroup_path}"/cgroup.procs
@@ -210,7 +210,7 @@ cgroup2_kill_cgroup() {
local cgroup_path
cgroup_path="$(cgroup2_find_path)"
[ -z "${cgroup_path}" ] && return 1
rc_cgroup_path="${cgroup_path}/${RC_SVCNAME}"
rc_cgroup_path="${cgroup_path}/openrc.${RC_SVCNAME}"
if [ -f "${rc_cgroup_path}"/cgroup.kill ]; then
printf "%d" 1 > "${rc_cgroup_path}"/cgroup.kill
fi

View File

@@ -30,6 +30,8 @@ supervise_start()
${chroot:+--chroot} $chroot \
${output_log+--stdout} ${output_log} \
${error_log+--stderr} $error_log \
${output_logger:+--stdout-logger \"$output_logger\"} \
${error_logger:+--stderr-logger \"$error_logger\"} \
${pidfile:+--pidfile} $pidfile \
${respawn_delay:+--respawn-delay} $respawn_delay \
${respawn_max:+--respawn-max} $respawn_max \
@@ -38,7 +40,7 @@ supervise_start()
${healthcheck_timer:+--healthcheck-timer} $healthcheck_timer \
${capabilities+--capabilities} "$capabilities" \
${secbits:+--secbits} "$secbits" \
${no_new_privs:+--no_new_privs} \
${no_new_privs:+--no-new-privs} \
${command_user+--user} $command_user \
${umask+--umask} $umask \
${supervise_daemon_args-${start_stop_daemon_args}} \

View File

@@ -78,7 +78,7 @@ int main(int argc, char **argv)
if (strcmp(applet, "eend") == 0 ||
strcmp(applet, "ewend") == 0 ||
strcmp(applet, "veend") == 0 ||
strcmp(applet, "vweend") == 0 ||
strcmp(applet, "vewend") == 0 ||
strcmp(applet, "ewaitfile") == 0)
{
errno = 0;

View File

@@ -23,6 +23,7 @@
#include <string.h>
#include <unistd.h>
#include <stdbool.h>
#include <spawn.h>
/* Yay for linux and its non liking of POSIX functions.
Okay, we could use getfsent but the man page says use getmntent instead
@@ -63,6 +64,8 @@
#include "_usage.h"
#include "helpers.h"
extern char **environ;
const char *applet = NULL;
const char *extraopts = NULL;
const char getoptstring[] = "MRbmop:t:" getoptstring_COMMON;
@@ -112,7 +115,7 @@ do_mount(struct ENT *ent, bool remount)
{
char *argv[10];
pid_t pid;
int status;
int status, err;
argv[0] = UNCONST("mount");
argv[1] = UNCONST("-o");
@@ -137,23 +140,14 @@ do_mount(struct ENT *ent, bool remount)
argv[8] = NULL;
#endif
}
switch (pid = vfork()) {
case -1:
eerrorx("%s: vfork: %s", applet, strerror(errno));
/* NOTREACHED */
case 0:
execvp(argv[0], argv);
eerror("%s: execvp: %s", applet, strerror(errno));
_exit(EXIT_FAILURE);
/* NOTREACHED */
default:
waitpid(pid, &status, 0);
if (WIFEXITED(status))
return WEXITSTATUS(status);
else
return -1;
/* NOTREACHED */
}
err = posix_spawnp(&pid, argv[0], NULL, NULL, argv, environ);
if (err)
eerrorx("%s: posix_spawnp: %s", applet, strerror(err));
while (waitpid(pid, &status, 0) < 0 && errno == EINTR);
if (WIFEXITED(status))
return WEXITSTATUS(status);
else
return -1;
}
#define OUTPUT_FILE (1 << 1)

View File

@@ -69,22 +69,22 @@ void elog(int, const char * EINFO_RESTRICT, ...) EINFO_PRINTF(2, 3);
* The x suffix means function will exit() returning failure.
*/
/*@{*/
int einfon(const char * __EINFO_RESTRICT, ...) EINFO_PRINTF(1, 2);
int ewarnn(const char * __EINFO_RESTRICT, ...) EINFO_PRINTF(1, 2);
int eerrorn(const char * __EINFO_RESTRICT, ...) EINFO_PRINTF(1, 2);
int einfo(const char * __EINFO_RESTRICT, ...) EINFO_PRINTF(1, 2);
int ewarn(const char * __EINFO_RESTRICT, ...) EINFO_PRINTF(1, 2);
void ewarnx(const char * __EINFO_RESTRICT, ...) EINFO_XPRINTF(1, 2);
int eerror(const char * __EINFO_RESTRICT, ...) EINFO_PRINTF(1, 2);
void eerrorx(const char * __EINFO_RESTRICT, ...) EINFO_XPRINTF(1, 2);
int einfon(const char * EINFO_RESTRICT, ...) EINFO_PRINTF(1, 2);
int ewarnn(const char * EINFO_RESTRICT, ...) EINFO_PRINTF(1, 2);
int eerrorn(const char * EINFO_RESTRICT, ...) EINFO_PRINTF(1, 2);
int einfo(const char * EINFO_RESTRICT, ...) EINFO_PRINTF(1, 2);
int ewarn(const char * EINFO_RESTRICT, ...) EINFO_PRINTF(1, 2);
void ewarnx(const char * EINFO_RESTRICT, ...) EINFO_XPRINTF(1, 2);
int eerror(const char * EINFO_RESTRICT, ...) EINFO_PRINTF(1, 2);
void eerrorx(const char * EINFO_RESTRICT, ...) EINFO_XPRINTF(1, 2);
int einfovn(const char * __EINFO_RESTRICT, ...) EINFO_PRINTF(1, 2);
int ewarnvn(const char * __EINFO_RESTRICT, ...) EINFO_PRINTF(1, 2);
int ebeginvn(const char * __EINFO_RESTRICT, ...) EINFO_PRINTF(1, 2);
int eendvn(int, const char * __EINFO_RESTRICT, ...) EINFO_PRINTF(2, 3);
int ewendvn(int, const char * __EINFO_RESTRICT, ...) EINFO_PRINTF(2, 3);
int einfov(const char * __EINFO_RESTRICT, ...) EINFO_PRINTF(1, 2);
int ewarnv(const char * __EINFO_RESTRICT, ...) EINFO_PRINTF(1, 2);
int einfovn(const char * EINFO_RESTRICT, ...) EINFO_PRINTF(1, 2);
int ewarnvn(const char * EINFO_RESTRICT, ...) EINFO_PRINTF(1, 2);
int ebeginvn(const char * EINFO_RESTRICT, ...) EINFO_PRINTF(1, 2);
int eendvn(int, const char * EINFO_RESTRICT, ...) EINFO_PRINTF(2, 3);
int ewendvn(int, const char * EINFO_RESTRICT, ...) EINFO_PRINTF(2, 3);
int einfov(const char * EINFO_RESTRICT, ...) EINFO_PRINTF(1, 2);
int ewarnv(const char * EINFO_RESTRICT, ...) EINFO_PRINTF(1, 2);
/*@}*/
/*! @ingroup ebegin

View File

@@ -4,7 +4,7 @@
*/
/*
* Copyright (c) 2007-2015 The OpenRC Authors.
* Copyright (c) 2007-2024 The OpenRC Authors.
* See the Authors file at the top-level directory of this distribution and
* https://github.com/OpenRC/openrc/blob/HEAD/AUTHORS
*
@@ -26,9 +26,6 @@
#include <string.h>
#include <strings.h>
#include <syslog.h>
#ifdef HAVE_TERMCAP
# include <termcap.h>
#endif
#include <unistd.h>
#include "einfo.h"
@@ -53,8 +50,7 @@
#define HILITE 6
#define BRACKET 4
/* We fallback to these escape codes if termcap isn't available
* like say /usr isn't mounted */
/* ANSI escape codes which mimic termcap */
#define AF "\033[3%dm"
#define CE "\033[K"
#define CH "\033[%dC"
@@ -97,13 +93,7 @@ static char *goto_column = NULL;
static const char *term = NULL;
static bool term_is_cons25 = false;
/* Termcap buffers and pointers
* Static buffers suck hard, but some termcap implementations require them */
#ifdef HAVE_TERMCAP
static char termcapbuf[2048];
static char tcapbuf[512];
#else
/* No curses support, so we hardcode a list of colour capable terms
/* Hardcoded list of colour capable terms
* Only terminals without "color" in the name need to be explicitly listed */
static const char *const color_terms[] = {
"Eterm",
@@ -142,13 +132,11 @@ static const char *const color_terms[] = {
"wsvt25",
"xterm",
"xterm-debian",
"xterm-kitty",
NULL
};
#endif
/* strlcat and strlcpy are nice, shame glibc does not define them */
#ifdef __GLIBC__
# if !defined (__UCLIBC__) && !defined (__dietlibc__)
#ifndef HAVE_STRLCPY
static size_t
strlcat(char *dst, const char *src, size_t size)
{
@@ -176,7 +164,6 @@ strlcat(char *dst, const char *src, size_t size)
return dst_n + (s - src);
}
# endif
#endif
static bool
@@ -239,7 +226,6 @@ is_verbose(void)
}
/* Fake tgoto call - very crapy, but works for our needs */
#ifndef HAVE_TERMCAP
static char *
tgoto(const char *cap, int col, int line)
{
@@ -302,7 +288,6 @@ tgoto(const char *cap, int col, int line)
*p = '\0';
return buf;
}
#endif
static bool
colour_terminal(FILE * EINFO_RESTRICT f)
@@ -315,9 +300,6 @@ colour_terminal(FILE * EINFO_RESTRICT f)
const char *bold;
char tmp[100];
unsigned int i = 0;
#ifdef HAVE_TERMCAP
char *bp;
#endif
if (f && !isatty(fileno(f)))
return false;
@@ -339,65 +321,33 @@ colour_terminal(FILE * EINFO_RESTRICT f)
if (strcmp(term, "cons25") == 0)
term_is_cons25 = true;
#ifdef HAVE_TERMCAP
/* Check termcap to see if we can do colour or not */
if (tgetent(termcapbuf, term) == 1) {
bp = tcapbuf;
_af = tgetstr("AF", &bp);
_ce = tgetstr("ce", &bp);
_ch = tgetstr("ch", &bp);
/* Our ch use also works with RI .... for now */
if (!_ch)
_ch = tgetstr("RI", &bp);
_md = tgetstr("md", &bp);
_me = tgetstr("me", &bp);
_up = tgetstr("up", &bp);
}
if (strstr(term, "color"))
in_colour = 1;
/* Cheat here as vanilla BSD has the whole termcap info in /usr
* which is not available to us when we boot */
if (term_is_cons25 || strcmp(term, "wsvt25") == 0) {
#else
if (strstr(term, "color"))
while (color_terms[i] && in_colour != 1) {
if (strcmp(color_terms[i], term) == 0) {
in_colour = 1;
while (color_terms[i] && in_colour != 1) {
if (strcmp(color_terms[i], term) == 0) {
in_colour = 1;
}
i++;
}
if (in_colour != 1) {
in_colour = 0;
return false;
}
#endif
if (!_af)
_af = AF;
if (!_ce)
_ce = CE;
if (!_ch)
_ch = CH;
if (!_md)
_md = MD;
if (!_me)
_me = ME;
if (!_up)
_up = UP;
#ifdef HAVE_TERMCAP
i++;
}
if (!_af || !_ce || !_me || !_md || !_up) {
if (in_colour != 1) {
in_colour = 0;
return false;
}
/* Many termcap databases don't have ch or RI even though they
* do work */
if (!_af)
_af = AF;
if (!_ce)
_ce = CE;
if (!_ch)
_ch = CH;
#endif
if (!_md)
_md = MD;
if (!_me)
_me = ME;
if (!_up)
_up = UP;
/* Now setup our colours */
p = ebuffer;

View File

@@ -1,9 +1,7 @@
libeinfo_version = '1'
libeinfo = library('einfo', ['libeinfo.c'],
c_args : termcap_flags,
include_directories : incdir,
dependencies : termcap_dep,
link_depends : 'einfo.map',
version : libeinfo_version,
install : true,

View File

@@ -402,7 +402,7 @@ rc_service_daemon_set(const char *service, const char *exec,
bool retval = false;
DIR *dp;
struct dirent *d;
RC_STRINGLIST *match;
RC_STRINGLIST *match, *renamelist;
int i = 0;
FILE *fp;
@@ -416,11 +416,17 @@ rc_service_daemon_set(const char *service, const char *exec,
/* Regardless, erase any existing daemon info */
if ((dp = opendir(dirpath))) {
match = _match_list(exec, argv, pidfile);
renamelist = rc_stringlist_new();
while ((d = readdir(dp))) {
if (d->d_name[0] == '.')
continue;
xasprintf(&file, "%s/%s", dirpath, d->d_name);
if (rc_stringlist_find(renamelist, file)) {
free(file);
continue;
}
nfiles++;
if (!*oldfile) {
@@ -432,11 +438,15 @@ rc_service_daemon_set(const char *service, const char *exec,
} else {
rename(file, oldfile);
strlcpy(oldfile, file, sizeof(oldfile));
/* Add renamed file to renamelist, as this new file name could
* be read again from readdir() */
rc_stringlist_add(renamelist, oldfile);
}
free(file);
}
closedir(dp);
rc_stringlist_free(match);
rc_stringlist_free(renamelist);
}
/* Now store our daemon info */

View File

@@ -287,6 +287,7 @@ static RC_STRINGLIST *rc_config_kcl(RC_STRINGLIST *config)
overrides = rc_stringlist_new();
/* A list of variables which may be overridden on the kernel command line */
rc_stringlist_add(overrides, "rc_interactive");
rc_stringlist_add(overrides, "rc_parallel");
TAILQ_FOREACH(override, overrides, entries) {

View File

@@ -6,12 +6,3 @@ executable('openrc-run',
include_directories: [incdir, einfo_incdir, rc_incdir],
install: true,
install_dir: sbindir)
executable('runscript',
['openrc-run.c', misc_c, plugin_c, selinux_c, usage_c, version_h],
c_args : [cc_audit_flags, cc_branding_flags, cc_pam_flags, cc_selinux_flags],
link_with: [libeinfo, librc],
dependencies: [audit_dep, dl_dep, pam_dep, pam_misc_dep, selinux_dep, util_dep, crypt_dep],
include_directories: [incdir, einfo_incdir, rc_incdir],
install: true,
install_dir: sbindir)

View File

@@ -107,7 +107,8 @@ static RC_STRINGLIST *deptypes_mwua; /* need+want+use+after deps for stopping */
static void
handle_signal(int sig)
{
int serrno = errno;
int serrno = errno, status;
pid_t pid;
const char *signame = NULL;
struct winsize ws;
@@ -117,12 +118,13 @@ handle_signal(int sig)
break;
case SIGCHLD:
if (signal_pipe[1] > -1) {
if (write(signal_pipe[1], &sig, sizeof(sig)) == -1)
eerror("%s: send: %s",
service, strerror(errno));
} else
rc_waitpid(-1);
while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
if (signal_pipe[1] > -1 && pid == service_pid) {
if (write(signal_pipe[1], &status, sizeof(status)) == -1)
eerror("%s: send: %s",
service, strerror(errno));
}
}
break;
case SIGWINCH:
@@ -438,6 +440,7 @@ svc_exec(const char *arg1, const char *arg2)
if (errno != EINTR) {
eerror("%s: poll: %s",
service, strerror(errno));
ret = -1;
break;
}
}
@@ -448,9 +451,20 @@ svc_exec(const char *arg1, const char *arg2)
write_prefix(buffer, bytes, &prefixed);
}
/* Only SIGCHLD signals come down this pipe */
if (fd[0].revents & (POLLIN | POLLHUP))
/* signal_pipe receives service_pid's exit status */
if (fd[0].revents & (POLLIN | POLLHUP)) {
if ((s = read(signal_pipe[0], &ret, sizeof(ret))) != sizeof(ret)) {
eerror("%s: receive failed: %s", service,
s < 0 ? strerror(errno) : "short read");
ret = -1;
break;
}
ret = WEXITSTATUS(ret);
if (ret != 0 && errno == ECHILD)
/* killall5 -9 could cause this */
ret = 0;
break;
}
}
}
@@ -473,11 +487,6 @@ svc_exec(const char *arg1, const char *arg2)
master_tty = -1;
}
ret = rc_waitpid(service_pid);
ret = WEXITSTATUS(ret);
if (ret != 0 && errno == ECHILD)
/* killall5 -9 could cause this */
ret = 0;
service_pid = 0;
return ret;
@@ -612,7 +621,7 @@ svc_start_check(void)
}
if (exclusive_fd == -1)
exclusive_fd = svc_lock(applet);
exclusive_fd = svc_lock(applet, !deps);
if (exclusive_fd == -1) {
if (errno == EACCES)
eerrorx("%s: superuser access required", applet);
@@ -864,7 +873,7 @@ svc_stop_check(RC_SERVICE *state)
exit(EXIT_FAILURE);
if (exclusive_fd == -1)
exclusive_fd = svc_lock(applet);
exclusive_fd = svc_lock(applet, !deps);
if (exclusive_fd == -1) {
if (errno == EACCES)
eerrorx("%s: superuser access required", applet);
@@ -1041,26 +1050,6 @@ svc_stop(void)
static void
svc_restart(void)
{
/* This is hairy and a better way needs to be found I think!
* The issue is this - openvpn need net and dns. net can restart
* dns via resolvconf, so you could have openvpn trying to restart
* dnsmasq which in turn is waiting on net which in turn is waiting
* on dnsmasq.
* The work around is for resolvconf to restart its services with
* --nodeps which means just that.
* The downside is that there is a small window when our status is
* invalid.
* One workaround would be to introduce a new status,
* or status locking. */
if (!deps) {
RC_SERVICE state = rc_service_state(service);
if (state & RC_SERVICE_STARTED || state & RC_SERVICE_INACTIVE)
svc_exec("stop", "start");
else
svc_exec("start", NULL);
return;
}
if (!(rc_service_state(service) & RC_SERVICE_STOPPED)) {
get_started_services();
svc_stop();
@@ -1108,7 +1097,6 @@ 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 = NULL;
@@ -1126,8 +1114,6 @@ int main(int argc, char **argv)
}
applet = basename_c(argv[0]);
if (strcmp(applet, "runscript") == 0)
runscript = true;
if (stat(argv[1], &stbuf) != 0) {
fprintf(stderr, "openrc-run `%s': %s\n",
@@ -1300,9 +1286,6 @@ 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

@@ -6,12 +6,3 @@ executable('openrc',
include_directories: [incdir, einfo_incdir, rc_incdir],
install: true,
install_dir: sbindir)
executable('rc',
['rc.c', 'rc-logger.c', misc_c, plugin_c, usage_c, version_h],
c_args : cc_branding_flags,
link_with: [libeinfo, librc],
dependencies: [dl_dep, util_dep],
include_directories: [incdir, einfo_incdir, rc_incdir],
install: true,
install_dir: sbindir)

View File

@@ -87,6 +87,7 @@ static RC_HOOK hook_out;
struct termios *termios_orig = NULL;
RC_PIDLIST service_pids;
RC_PIDLIST free_these_pids;
static void
clean_failed(void)
@@ -116,8 +117,7 @@ clean_failed(void)
static void
cleanup(void)
{
RC_PID *p1 = LIST_FIRST(&service_pids);
RC_PID *p2;
RC_PID *p, *tmp;
if (!rc_in_logger && !rc_in_plugin &&
applet && (strcmp(applet, "rc") == 0 || strcmp(applet, "openrc") == 0))
@@ -139,10 +139,13 @@ cleanup(void)
rc_logger_close();
}
while (p1) {
p2 = LIST_NEXT(p1, entries);
free(p1);
p1 = p2;
LIST_FOREACH_SAFE(p, &service_pids, entries, tmp) {
LIST_REMOVE(p, entries);
free(p);
}
LIST_FOREACH_SAFE(p, &free_these_pids, entries, tmp) {
LIST_REMOVE(p, entries);
free(p);
}
rc_stringlist_free(main_hotplugged_services);
@@ -344,22 +347,46 @@ static char *get_krunlevel(void)
static void
add_pid(pid_t pid)
{
sigset_t sset, old;
RC_PID *p = xmalloc(sizeof(*p));
p->pid = pid;
/* this list will be accessed inside the SIGCHLD signal handler.
* so we need to ensure that the SIGCHLD handler doesn't get invoked
* while the list is at an inconsistent state.
*/
sigemptyset(&sset);
sigaddset(&sset, SIGCHLD);
sigprocmask(SIG_SETMASK, &sset, &old);
LIST_INSERT_HEAD(&service_pids, p, entries);
sigprocmask(SIG_SETMASK, &old, NULL);
}
static void
remove_pid(pid_t pid)
remove_pid(pid_t pid, bool inside_signal)
{
RC_PID *p;
sigset_t sset, old;
RC_PID *p, *tmp;
LIST_FOREACH(p, &service_pids, entries)
if (p->pid == pid) {
LIST_REMOVE(p, entries);
free(p);
return;
}
/* same rationale for blocking SIGCHLD as add_pid() */
sigemptyset(&sset);
sigaddset(&sset, SIGCHLD);
sigprocmask(SIG_SETMASK, &sset, &old);
LIST_FOREACH(p, &service_pids, entries) {
if (p->pid == pid) {
LIST_REMOVE(p, entries);
LIST_INSERT_HEAD(&free_these_pids, p, entries);
break;
}
}
/* only call free if we're not inside a signal handler */
if (!inside_signal) {
LIST_FOREACH_SAFE(p, &free_these_pids, entries, tmp) {
LIST_REMOVE(p, entries);
free(p);
}
}
sigprocmask(SIG_SETMASK, &old, NULL);
}
static void
@@ -397,7 +424,7 @@ handle_signal(int sig)
/* Remove that pid from our list */
if (pid > 0)
remove_pid(pid);
remove_pid(pid, true);
break;
case SIGWINCH:
@@ -500,7 +527,7 @@ runlevel_config(const char *service, const char *level)
char *conf, *dir;
bool retval;
dir = dirname(init);
dir = dirname(dirname(init));
xasprintf(&conf, "%s/conf.d/%s.%s", dir, service, level);
retval = exists(conf);
free(conf);
@@ -606,7 +633,7 @@ stop:
add_pid(pid);
if (!parallel) {
rc_waitpid(pid);
remove_pid(pid);
remove_pid(pid, false);
}
}
}
@@ -672,7 +699,7 @@ do_start_services(const RC_STRINGLIST *start_services, bool parallel)
add_pid(pid);
if (!parallel) {
rc_waitpid(pid);
remove_pid(pid);
remove_pid(pid, false);
}
}
}
@@ -745,6 +772,7 @@ int main(int argc, char **argv)
applet = basename_c(argv[0]);
LIST_INIT(&service_pids);
LIST_INIT(&free_these_pids);
atexit(cleanup);
if (!applet)
eerrorx("arguments required");
@@ -809,8 +837,6 @@ int main(int argc, char **argv)
}
}
if (strcmp(applet, "rc") == 0)
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

@@ -88,7 +88,7 @@ delete(const char *runlevel, const char *service)
errno = 0;
if (rc_service_delete(runlevel, service)) {
einfo("service %s removed from runlevel %s",
einfo("service %s deleted from runlevel %s",
service, runlevel);
return 1;
}
@@ -97,7 +97,7 @@ delete(const char *runlevel, const char *service)
eerror("%s: service `%s' is not in the runlevel `%s'",
applet, service, runlevel);
else
eerror("%s: failed to remove service `%s' from runlevel `%s': %s",
eerror("%s: failed to delete service `%s' from runlevel `%s': %s",
applet, service, runlevel, strerror (errno));
return retval;
@@ -144,7 +144,7 @@ static int
delstack(const char *runlevel, const char *stack)
{
if (rc_runlevel_unstack(runlevel, stack)) {
einfo("runlevel %s removed from runlevel %s", stack, runlevel);
einfo("runlevel %s deleted from runlevel %s", stack, runlevel);
return 1;
}
@@ -152,7 +152,7 @@ delstack(const char *runlevel, const char *stack)
eerror("%s: runlevel `%s' is not in the runlevel `%s'",
applet, stack, runlevel);
else
eerror("%s: failed to remove runlevel `%s' from runlevel `%s': %s",
eerror("%s: failed to delete runlevel `%s' from runlevel `%s': %s",
applet, stack, runlevel, strerror (errno));
return -1;

View File

@@ -37,10 +37,8 @@
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
#ifdef __GLIBC__
# if !defined (__UCLIBC__) && !defined (__dietlibc__)
#ifndef HAVE_STRLCPY
# define strlcpy(dst, src, size) snprintf(dst, size, "%s", src)
# endif
#endif
#ifndef timespecsub

View File

@@ -10,6 +10,10 @@ schedules_c = files([
'schedules.c',
])
pipes_c = files([
'pipes.c',
])
if selinux_dep.found()
selinux_c = files([
'selinux.c',

View File

@@ -15,10 +15,18 @@
* except according to the terms contained in the LICENSE file.
*/
#ifdef HAVE_CLOSE_RANGE
/* For close_range() */
# define _GNU_SOURCE
#endif
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#ifdef HAVE_LINUX_CLOSE_RANGE_H
# include <linux/close_range.h>
#endif
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
@@ -26,6 +34,7 @@
#include <sys/file.h>
#include <sys/time.h>
#ifdef __linux__
# include <sys/syscall.h> /* for close_range */
# include <sys/sysinfo.h>
#endif
#include <sys/types.h>
@@ -234,7 +243,7 @@ signal_setup_restart(int sig, void (*handler)(int))
}
int
svc_lock(const char *applet)
svc_lock(const char *applet, bool ignore_lock_failure)
{
char *file = NULL;
int fd;
@@ -245,6 +254,14 @@ svc_lock(const char *applet)
if (fd == -1)
return -1;
if (flock(fd, LOCK_EX | LOCK_NB) == -1) {
if (ignore_lock_failure) {
/* Two services with a need b, and b's start()
* calling restart --no-deps on a would cause
* harmless errors: just ignore them.
* See https://github.com/OpenRC/openrc/issues/224
*/
exit(EXIT_SUCCESS);
}
eerror("Call to flock failed: %s", strerror(errno));
close(fd);
return -1;
@@ -274,7 +291,7 @@ exec_service(const char *service, const char *arg)
sigset_t old;
struct sigaction sa;
fd = svc_lock(basename_c(service));
fd = svc_lock(basename_c(service), false);
if (fd == -1)
return -1;
@@ -492,3 +509,30 @@ pid_t get_pid(const char *applet,const char *pidfile)
return pid;
}
#ifndef HAVE_CLOSE_RANGE
static inline int close_range(int first RC_UNUSED,
int last RC_UNUSED,
unsigned int flags RC_UNUSED)
{
#ifdef SYS_close_range
return syscall(SYS_close_range, first, last, flags);
#else
errno = ENOSYS;
return -1;
#endif
}
#endif
#ifndef CLOSE_RANGE_CLOEXEC
# define CLOSE_RANGE_CLOEXEC (1U << 2)
#endif
void
cloexec_fds_from(int first)
{
int i;
if (close_range(first, UINT_MAX, CLOSE_RANGE_CLOEXEC) < 0) {
for (i = getdtablesize() - 1; i >= first; --i)
fcntl(i, F_SETFD, FD_CLOEXEC);
}
}

View File

@@ -50,7 +50,7 @@ void env_filter(void);
void env_config(void);
int signal_setup(int sig, void (*handler)(int));
int signal_setup_restart(int sig, void (*handler)(int));
int svc_lock(const char *);
int svc_lock(const char *, bool);
int svc_unlock(const char *, int);
pid_t exec_service(const char *, const char *);
@@ -73,4 +73,6 @@ void from_time_t(char *time_string, time_t tv);
time_t to_time_t(char *timestring);
pid_t get_pid(const char *applet, const char *pidfile);
void cloexec_fds_from(int);
#endif

View File

@@ -1,5 +1,5 @@
executable('start-stop-daemon',
['start-stop-daemon.c', 'pipes.c', misc_c, schedules_c,
['start-stop-daemon.c', pipes_c, misc_c, schedules_c,
selinux_c, usage_c, version_h],
c_args : [cc_audit_flags, cc_branding_flags, cc_pam_flags, cc_cap_flags, cc_selinux_flags],
link_with: [libeinfo, librc],

View File

@@ -1098,12 +1098,7 @@ int main(int argc, char **argv)
|| rc_yesno(getenv("EINFO_QUIET")))
dup2(stderr_fd, STDERR_FILENO);
#ifdef HAVE_CLOSEFROM
closefrom(3);
#else
for (i = getdtablesize() - 1; i >= 3; --i)
close(i);
#endif
cloexec_fds_from(3);
if (scheduler != NULL) {
int scheduler_index;

View File

@@ -1,5 +1,5 @@
executable('supervise-daemon',
['supervise-daemon.c', misc_c, plugin_c, schedules_c, usage_c, version_h],
['supervise-daemon.c', pipes_c, misc_c, plugin_c, schedules_c, usage_c, version_h],
c_args : [cc_branding_flags, cc_pam_flags, cc_cap_flags, cc_selinux_flags],
link_with: [libeinfo, librc],
dependencies: [dl_dep, pam_dep, cap_dep, util_dep, selinux_dep],

View File

@@ -22,11 +22,6 @@
#define ONE_SECOND 1000000000
#define ONE_MS 1000000
#ifdef HAVE_CLOSE_RANGE_CLOEXEC
/* For close_range() */
# define _GNU_SOURCE
#endif
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
@@ -67,6 +62,7 @@ static struct pam_conv conv = { NULL, NULL};
#include "queue.h"
#include "rc.h"
#include "misc.h"
#include "pipes.h"
#include "plugin.h"
#include "schedules.h"
#include "_usage.h"
@@ -84,6 +80,8 @@ enum {
LONGOPT_OOM_SCORE_ADJ,
LONGOPT_NO_NEW_PRIVS,
LONGOPT_SECBITS,
LONGOPT_STDERR_LOGGER,
LONGOPT_STDOUT_LOGGER,
};
const char *applet = NULL;
@@ -115,6 +113,8 @@ const struct option longopts[] = {
{ "user", 1, NULL, 'u'},
{ "stdout", 1, NULL, '1'},
{ "stderr", 1, NULL, '2'},
{ "stdout-logger",1, NULL, LONGOPT_STDOUT_LOGGER},
{ "stderr-logger",1, NULL, LONGOPT_STDERR_LOGGER},
{ "reexec", 0, NULL, '3'},
longopts_COMMON
};
@@ -143,6 +143,8 @@ const char * const longopts_help[] = {
"Change the process user",
"Redirect stdout to file",
"Redirect stderr to file",
"Redirect stdout to process",
"Redirect stderr to process",
"reexec (used internally)",
longopts_help_COMMON
};
@@ -165,6 +167,8 @@ static int stdout_fd;
static int stderr_fd;
static char *redirect_stderr = NULL;
static char *redirect_stdout = NULL;
static char *stderr_process = NULL;
static char *stdout_process = NULL;
#ifdef TIOCNOTTY
static int tty_fd = -1;
#endif
@@ -554,6 +558,12 @@ RC_NORETURN static void child_process(char *exec, char **argv)
eerrorx("%s: unable to open the logfile"
" for stdout `%s': %s",
applet, redirect_stdout, strerror(errno));
} else if (stdout_process) {
stdout_fd = rc_pipe_command(stdout_process);
if (stdout_fd == -1)
eerrorx("%s: unable to open the logging process"
" for stdout `%s': %s",
applet, stdout_process, strerror(errno));
}
if (redirect_stderr) {
if ((stderr_fd = open(redirect_stderr,
@@ -562,19 +572,22 @@ RC_NORETURN static void child_process(char *exec, char **argv)
eerrorx("%s: unable to open the logfile"
" for stderr `%s': %s",
applet, redirect_stderr, strerror(errno));
} else if (stderr_process) {
stderr_fd = rc_pipe_command(stderr_process);
if (stderr_fd == -1)
eerrorx("%s: unable to open the logging process"
" for stderr `%s': %s",
applet, stderr_process, strerror(errno));
}
dup2(stdin_fd, STDIN_FILENO);
if (redirect_stdout || rc_yesno(getenv("EINFO_QUIET")))
if (redirect_stdout || stdout_process || rc_yesno(getenv("EINFO_QUIET")))
dup2(stdout_fd, STDOUT_FILENO);
if (redirect_stderr || rc_yesno(getenv("EINFO_QUIET")))
if (redirect_stderr || stderr_process || rc_yesno(getenv("EINFO_QUIET")))
dup2(stderr_fd, STDERR_FILENO);
#ifdef HAVE_CLOSE_RANGE_CLOEXEC
if (close_range(3, UINT_MAX, CLOSE_RANGE_CLOEXEC) < 0)
#endif
for (i = getdtablesize() - 1; i >= 3; --i)
fcntl(i, F_SETFD, FD_CLOEXEC);
cloexec_fds_from(3);
cmdline = make_cmdline(argv);
syslog(LOG_INFO, "Child command line: %s", cmdline);
free(cmdline);
@@ -1047,6 +1060,14 @@ int main(int argc, char **argv)
reexec = true;
break;
case LONGOPT_STDOUT_LOGGER: /* --stdout-logger "command to run for stdout logging" */
stdout_process = optarg;
break;
case LONGOPT_STDERR_LOGGER: /* --stderr-logger "command to run for stderr logging" */
stderr_process = optarg;
break;
case_RC_COMMON_GETOPT
}

View File

@@ -1,55 +1,54 @@
Using supervise-daemon
======================
# 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
`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
* **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 daemon that you would like to have monitored by supervise-daemon
* **Daemons must not fork**.
Any daemon that you would like to have monitored by `supervise-daemon`
must not fork. Instead, it must stay in the foreground. If the daemon
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
instructs it not to fork to the `command_args_foreground` variable shown
below.
# Health Checks
## Health checks
Health checks are a way to make sure a service monitored by
supervise-daemon stays healthy. To configure a health check for a
service, you need to write a healthcheck() function, and optionally an
unhealthy() function in the service script. Also, you will need to set
the healthcheck_timer and optionally healthcheck_delay variables.
`supervise-daemon` stays healthy. To configure a health check for a
service, you need to write a `healthcheck()` function, and optionally an
`unhealthy()` function in the service script. Also, you will need to set
the `healthcheck_timer` and optionally `healthcheck_delay` variables.
## healthcheck() function
### healthcheck() function
The healthcheck() function is run repeatedly based on the settings of
the healthcheck_* variables. This function should return zero if the
The `healthcheck()` function is run repeatedly based on the settings of
the `healthcheck_*` variables. This function should return zero if the
service is currently healthy or non-zero otherwise.
## unhealthy() function
### unhealthy() function
If the healthcheck() function returns non-zero, the unhealthy() function
If the `healthcheck()` function returns non-zero, the `unhealthy()` function
is run, then the service is restarted. Since the service will be
restarted by the supervisor, the unhealthy function should not try to
restart it; the purpose of the function is to allow any cleanup tasks
other than restarting the service to be run.
# Variable Settings
## Variable settings
The most important setting is the supervisor variable. At the top of
your service script, you should set this variable as follows:
``` sh
```sh
supervisor=supervise-daemon
```
@@ -57,29 +56,29 @@ 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:
``` sh
```sh
command_args_foreground="arguments"
```
This should be used if the daemon you want to monitor
This 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.
``` sh
```sh
healthcheck_delay=seconds
```
This is the delay, in seconds, before the first health check is run.
If it is not set, we use the value of healthcheck_timer.
If it is not set, we use the value of `healthcheck_timer`.
``` sh
```sh
healthcheck_timer=seconds
```
This is the number of seconds between health checks. If it is not set,
no health checks will be run.
``` sh
```sh
respawn_delay
```
@@ -87,7 +86,7 @@ This is the number of seconds to delay before attempting to respawn a
supervised process after it dies unexpectedly.
The default is to respawn immediately.
``` sh
```sh
respawn_max=x
```
@@ -95,17 +94,17 @@ This is the maximum number of times to respawn a supervised process
during the given respawn period.
The default is 10. 0 means unlimited.
``` sh
```sh
respawn_period=seconds
```
This works in conjunction with respawn_max and respawn_delay above to
This works in conjunction with `respawn_max` and `respawn_delay` above to
decide if a process should not be respawned for some reason.
For example, if respawn period is 10 and respawn_max is 2, the process
For example, if respawn period is 10 and `respawn_max` is 2, the process
would need to die 3 times within 10 seconds to no longer be respawned.
Note that respawn_delay will delay all of this, so in the above scenario
a respawn_delay of greater than 5 will cause infinite respawns.
Note that `respawn_delay` will delay all of this, so in the above scenario
a `respawn_delay` of greater than 5 will cause infinite respawns.
By default, this is unset and respawn_max applies to the entire lifetime
By default, this is unset and `respawn_max` applies to the entire lifetime
of the service.

View File

@@ -11,8 +11,7 @@ sysvinit="$4"
if [ "${os}" != Linux ]; then
install -d "${DESTDIR}/${rc_libexecdir}"/init.d
fi
install -d "${DESTDIR}/${rc_libexecdir}"/tmp
install -m 644 "${MESON_BUILD_ROOT}/src/shared/version" "${DESTDIR}/${rc_libexecdir}"
if [ "${os}" = Linux ] && [ "${sysvinit}" = yes ]; then
ln -s openrc-init "${DESTDIR}/${sbindir}"/init
ln -sf openrc-init "${DESTDIR}/${sbindir}"/init
fi