Compare commits

..

205 Commits
0.31.2 ... 0.39

Author SHA1 Message Date
William Hubbs
53f7afd3b3 Update ChangeLog 2018-10-23 17:14:01 -05:00
William Hubbs
75e9b66f6f news.md: add information about the modules service changes 2018-10-23 16:59:20 -05:00
William Hubbs
d70b1c55b6 modules: Add --first-time switch to modprobe commands
On Linux, kernel modules should be loaded once during boot, either in an
initramfs or by this service.

This does not change anything other than printing out messages if a
module is loaded more than once.

X-Gentoo-Bug: 659530
X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=659530
2018-10-23 16:47:37 -05:00
William Hubbs
c1e582586d supervise-daemon: add health checks
Health checks are a way to monitor a service and make sure it stays
healthy.

If a service is not healthy, it will be automatically restarted after
running the unhealthy() function to clean up.
2018-10-23 13:38:14 -05:00
William Hubbs
7a75bfb00c news.md: add note about scheduled shutdown 2018-10-23 13:34:08 -05:00
William Hubbs
aacf841de4 supervise-daemon-guide.md: re-format and add more variables 2018-10-22 17:49:25 -05:00
William Hubbs
3f918161aa openrc-shutdown: Add scheduled shutdown and the ability to cancel a shutdown
You can now schedule a shutdown for a certain time or a cpecific number
of minutes into the future.

When a shutdown is running, you can now cancel it with ^c from the
keyboard or by running "openrc-shutdown -c" from another shell.
2018-10-18 17:56:36 -05:00
Zac Medico
710c874e6e supervise-daemon: fix respawn_max off by one
Fix the comparison between respawn_count and respawn_max so that
respawn_max = 1 will allow for one respawn. Since respawn_count is
incremented before the comparison, use a 'greater than' comparison
so that respawn will be triggered when respawn_count is equal to
respawn_max.

Fixes: https://github.com/OpenRC/openrc/issues/247
Fixes: https://github.com/OpenRC/openrc/issues/248
2018-10-15 11:50:42 -05:00
Austin English
07908be090 misc: style fixups 2018-10-13 12:53:54 -04:00
Austin English
02af093043 misc: whitespace fixes 2018-10-13 12:53:54 -04:00
William Hubbs
67e2d6033d Complete implementation of forever timeout value in stop schedules 2018-10-09 11:34:52 -05:00
William Hubbs
eca4357892 supervise-daemon: use nanosleep() instead of sleep()
We will be using sigalrm in this process for health checking, and
sigalrm cannot be used with sleep() safely.
2018-10-06 12:51:04 -05:00
William Hubbs
7ee3e5b2d6 openrc-init: convert sleep() call to nanosleep()
Nanosleep is the safer call to use in case we need to use alarms
eventually.
2018-10-06 12:49:44 -05:00
William Hubbs
7cb8d94323 Stop mounting efivarfs read-only
We do not need to do this any longer since all supported linux kernels
make efivarfs immutable and the tools that manipulate it are aware of
this feature.

This fixes https://github.com/openrc/openrc/issues/238.
2018-08-14 10:21:27 -05:00
Zac Medico
84ed570eae librc: fix EACCES errno false-positive crash
Use errno != EACCES to fix false-positive for non-root users
with grsecurity kernels.

Fixes: 37e2944272 ("librc: Add check for crashed state")
This fixes #237
2018-08-06 17:39:52 -05:00
William Hubbs
2eea73bfd5 rc-functions.sh: Remove addon support
This is an old relic from Gentoo baselayout-1.x which should not be used
any longer.
2018-07-09 19:44:40 -05:00
William Hubbs
a571a42421 modules: remove the ability to rename modules on the fly
Kmod doesn't support the -o switch, so if you have been using this your
module loads have been failing.
2018-06-29 15:29:46 -05:00
Holger Hoffstätte
79648ac1c6 rc-status: initialize uptime pointer to prevent memory corruption
This fixes #231.
2018-06-29 08:49:13 -05:00
William Hubbs
02af762e83 version 0.39 2018-06-28 13:32:19 -05:00
William Hubbs
01c34c28e6 Update ChangeLog 2018-06-28 13:02:42 -05:00
William Hubbs
56ddda54b5 supervise-daemon.c: clean up memory leaks 2018-06-27 17:37:11 -05:00
William Hubbs
3a803b3135 librc-daemon.c: fix memory leaks 2018-06-27 12:06:19 -05:00
William Hubbs
72df51e17b librc-daemon: convert most snprintf calls to xasprintf 2018-06-22 15:41:25 -05:00
William Hubbs
b2f5531194 librc-misc: convert snprintf calls to xasprintf 2018-06-20 17:45:01 -05:00
William Hubbs
19bf49a710 libeinfo: convert remaining snprintf calls to xasprintf 2018-06-20 12:36:51 -05:00
William Hubbs
64354831da openrc: convert snprintf calls to xasprintf 2018-06-20 09:37:20 -05:00
William Hubbs
e14edd765f supervise-daemon: convert snprintf calls to xasprintf 2018-06-19 17:57:10 -05:00
William Hubbs
f9d41243d8 start-stop-daemon: convert snprintf calls to xasprintf 2018-06-19 17:46:12 -05:00
William Hubbs
be7ad06d4a rc-status: convert snprintf calls to xasprintf 2018-06-19 17:06:33 -05:00
William Hubbs
a616516895 rc-status: fix gcc 7 warnings 2018-06-19 16:18:48 -05:00
William Hubbs
04721ece03 start-stop-daemon: fix gcc 7 warnings 2018-06-19 15:32:10 -05:00
William Hubbs
c7e8f1133a checkpath: fix gcc 7 warnings 2018-06-19 14:01:54 -05:00
William Hubbs
47e4bfae57 fix gcc 7 warnings in pipe routines 2018-06-19 13:59:16 -05:00
William Hubbs
8a945194af libeinfo: clean up gcc 7 compiler warnings 2018-06-19 13:52:40 -05:00
William Hubbs
aa4a004c29 version 0.38 2018-06-17 12:45:51 -05:00
William Hubbs
9ec5d36bdd Update ChangeLog 2018-06-15 18:04:43 -05:00
William Hubbs
a097933eda sh/start-stop-daemon.sh: fix processing of the logger arguments 2018-06-15 17:44:39 -05:00
William Hubbs
a6f5b1bb63 Update ChangeLog 2018-06-15 12:59:13 -05:00
William Hubbs
e6d01471fe start-stop-daemon: add ability to log stdout or stderr to processes 2018-06-15 12:23:50 -05:00
William Hubbs
d4501a9f06 fix a typo 2018-06-14 14:55:42 -05:00
Mike Gilbert
ec8abea460 Add helper to spawn process with stdin connected to a pipe 2018-06-13 13:49:42 -05:00
William Hubbs
e4ddfa38e0 user-guide.md: small cleanups 2018-06-05 17:34:09 -05:00
William Hubbs
21d30bc6d9 service-script-guide.md: small cleanups 2018-06-05 17:26:57 -05:00
William Hubbs
2a1ff6e49c version 0.37 2018-06-05 16:11:28 -05:00
William Hubbs
6762cb875c Update ChangeLog 2018-05-31 16:53:25 -05:00
Austin English
6edf516a1f sh/supervise-daemon.sh: use start_stop_daemon_args if supervise_daemon_args is undefined 2018-05-30 12:11:10 -04:00
William Hubbs
7e56a49e23 Logger: only log printable characters and newlines
X-Gentoo-Bug: 651412
X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=651412
2018-05-22 17:11:43 -05:00
William Hubbs
fa5aea80c5 openrc-run.sh: move crashed test outside started test
This is handled inside librc, so we don't need the nesting in this
script.
2018-05-22 12:20:38 -05:00
William Hubbs
0f4fa41574 Add mark_service_crashed binary 2018-05-22 12:20:38 -05:00
William Hubbs
5d6dd97bba rc-misc: add the crashed state 2018-05-22 12:20:38 -05:00
William Hubbs
37e2944272 librc: Add check for crashed state
In rc_service_state,, call rc_service_daemons_crashed to check for
a crashed daemon if the service is started.
2018-05-22 12:19:41 -05:00
William Hubbs
4e0eace837 librc: Add crashed state 2018-05-22 12:19:22 -05:00
William Hubbs
faa8318b3b Remove the _rc_can_find_pids function
This test to find if we could see pid 1 was being used inconsistently in
rc-status and mark_service_crashed to decide whether we could test to
see if the daemon for the service was crashed, and it was not part of
the librc library.

I am removing it from the executables because of inconsistent usage. I
will add it to the library if it is needed there.
2018-05-18 16:48:21 -05:00
William Hubbs
08da36149c rc-service: add --ifstarted and --ifstopped options 2018-05-16 13:25:22 -05:00
William Hubbs
56870d0db1 Man: rc-service man page cleanups 2018-05-15 17:09:56 -05:00
William Hubbs
4d47ce440c rc-service: add -d/--debug and -D/--nodeps options 2018-05-15 16:59:21 -05:00
William Hubbs
958f57d895 openrc-run: respect the RC_NODEPS environment variable 2018-05-15 16:27:42 -05:00
William Hubbs
04886efd85 Add RC_DEBUG and RC_NODEPS to environment whitelist
These are needed so rc-service can pass debug and nodeps options to
openrc-run.
2018-05-15 16:18:19 -05:00
William Hubbs
d980798d64 openrc-run: respect the IN_DRYRUN environment variable
This allows rc-service to pass the tryrun option to openrc-run.

This is for #225.
2018-05-14 19:08:19 -05:00
William Hubbs
414a9aae6c rc-misc.c: Add IN_DRYRUN to environment whitelist
This allows rc-service to pass the dryrun option to openrc-run.

This is for #225.
2018-05-14 19:04:42 -05:00
William Hubbs
a7f475ca04 rc-service: add a --dry-run option
This is for #225.
2018-05-14 19:00:04 -05:00
William Hubbs
3c53680018 build: standardize installation modes
Gentoo was changing some of our installation modes from 0444 to 0644.
There isn't a reason to install things 0444, so we are switching these
to 0644 so the Gentoo ebuild doesn't need this extra step.
2018-05-11 15:38:27 -05:00
William Hubbs
f0ad647303 Revert "savecache: stop saving the dependency tree"
It is safe to save the deptree, but we also need to regenerate it at
boot time.
2018-05-11 11:54:48 -05:00
William Hubbs
b35e03b6b1 Revert "Logger: only log printable characters and newlines"
This reverts commit 2b1392af2f.
This seems to create issues shutting down, so I need to look into it
further.
2018-05-10 19:35:24 -05:00
William Hubbs
2b1392af2f Logger: only log printable characters and newlines
X-Gentoo-Bug: 651412
X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=651412
2018-05-09 17:30:08 -05:00
William Hubbs
a3d0e293ee Remove localmount from dependencies for linux-only services
This removes localmount from the dependencies of the consolefont,
keymaps, numlock and procfs services.

These services are Linux only and the default modern linux system has /
and /usr on the same file system.

This also fixes the following issue.

X-Gentoo-Bug: 651998
X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=651998
2018-05-07 18:12:55 -05:00
Andrey Utkin
0200002b8c start-stop-daemon: don't fail stopping if pidfile is gone
If pidfile does not exist when we are stopping the daemon, assume it is
already stopped, and report success.

hostapd is an example of a daemon which removes its pidfile when it is
exiting. If this daemon terminates prematurely, that is, without s-s-d
involvement, then openrc fails to restart it, because s-s-d "stop"
command fails when pidfile is missing.

X-Gentoo-Bug: 646274
X-Gentoo-Bug-URL: https://bugs.gentoo.org/646274
2018-05-02 13:42:59 -05:00
William Hubbs
f4e2142089 Add _POSIX_C_SOURCE definition to Linux build
We need this to allow builds on uclibc-ng based systems.

X-Gentoo-Bug: 650908
X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=650908
2018-05-01 13:29:13 -05:00
William Hubbs
49a90f27a8 typo fix 2018-04-24 10:40:57 -05:00
Scall
2ae60ca041 rc-update: fix typo 2018-03-21 08:33:33 -04:00
William Hubbs
6b475ab269 init.d/modules: add code from modules-load service
There is no reason for these to be separate services. I did add a
provide so that we don't break backward compatibility.
2018-03-16 14:33:01 -05:00
William Hubbs
b302b0c094 net-online: always start after net
X-Gentoo-Bug: 650600
X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=650600
2018-03-16 13:53:02 -05:00
William Hubbs
40aa69cf3a agetty.in: allow status to be displayed 2018-03-14 20:37:02 -05:00
William Hubbs
5346fbf2c9 supervise-daemon: fix off-by-one error 2018-03-14 20:05:45 -05:00
William Hubbs
92e6bdee12 Use _BSD_SOURCE on FreeBSD 2018-03-14 13:07:46 -05:00
William Hubbs
71f275b2aa typo fix 2018-03-14 10:45:40 -05:00
William Hubbs
6dc0d0af33 Remove _XOPEN_SOURCE macros from builds 2018-03-13 18:14:55 -05:00
William Hubbs
59a9e53378 Add _POSIX_C_SOURCE macro to FreeBSD build 2018-03-13 18:04:54 -05:00
William Hubbs
122768d339 man: document default retry specification for supervise-daemon 2018-03-12 18:22:40 -05:00
William Hubbs
fa3c60c0d8 man: document default retry sppecification for start-stop-daemon 2018-03-12 18:15:06 -05:00
William Hubbs
61905bfcf5 Clean up cgroups v2 code
Remove the IFS manipulation and simplify the loop that processes the
settings.
2018-03-11 21:41:01 -05:00
Scall
3e68013631 init.d: swap should always be started after root
Otherwise if a swap file is being used, and swap is started before
root, swapon may fail because of a read-only filesystem.
2018-03-05 20:16:26 -05:00
Chris Cromer
b46123f2e1 openrc-run: fix memory size (#213)
Fixes #212
2018-03-01 19:31:33 -05:00
William Hubbs
109869641f fix build on FreeBSD 2018-03-01 11:47:29 -06:00
William Hubbs
e8a2305de0 version 0.36 2018-03-01 11:46:02 -06:00
William Hubbs
f62975a1f8 Update ChangeLog 2018-02-28 16:21:52 -06:00
Jason Zaman
5bb6f9aa31 init.sh: apply SELinux label for /run early in boot
Some initramfs mount /run which then ends up with the wrong labels.
Force relabel all of /run right after its mounted to fix.
2018-02-28 12:42:58 -06:00
Jason Zaman
1ab8541a6c init-early.sh.Linux.in: apply the selinux label to /dev/console early
/dev/console is relabelled later in the devfs init script, but by then we
have already missed some of the messages, so fix that label early.
2018-02-28 11:24:55 -06:00
William Hubbs
038c03bef3 supervise-daemon: make an error message more verbose 2018-02-27 16:02:20 -06:00
William Hubbs
e51dc29e2f cgroups: fix indentation 2018-02-27 15:56:54 -06:00
William Hubbs
c6047f887a cgroups: add rc_cgroup_memory_use_hierarchy setting for cgroups v1 2018-02-26 14:33:15 -06:00
William Hubbs
0506d68427 fstabinfo: fix an error message 2018-02-26 13:46:47 -06:00
William Hubbs
c3d666acaf openrc: remove unused #define's. 2018-02-26 13:14:31 -06:00
William Hubbs
e93b1d76d1 openrc: convert another execl() call to execlp() 2018-02-26 13:13:44 -06:00
William Hubbs
acf1e43f81 openrc-init: convert execl calls to execlp 2018-02-26 12:21:14 -06:00
William Hubbs
f383fd87b1 kill_all: change execl call to execlp 2018-02-24 17:02:02 -06:00
William Hubbs
cfded513cd openrc-init: set a default path
The default path provided by the system if one isn't set only includes
"/bin:/usr/bin". This adds the default path setting from sysvinit.
2018-02-24 16:24:08 -06:00
Christian Brauner
16ff3cd8df check whether /sys/fs/cgroup is a mountpoint
The current check only tries to detect whether /sys/fs/cgroup exists and
whether it is writable or not. But when the init system doesn't mount
cgroups then /sys/fs/cgroup will just be an empty directory. When paired
with unprivileged containers that mount sysfs this will cause misleading
errors to be printed since /sys/fs/cgroup will be owned by user
nobody:nogroup in this case. Independent of this specific problem this
check will also be misleading when the /sys/fs/cgroup exists and is in
fact writable by the init system but isn't actually a mountpoint.

Note from William. "grep -qs" doesn't need to redirect output to
/dev/null since it is completely silent.

This fixes #209.
2018-02-23 15:51:12 -06:00
William Hubbs
38032626a6 improve cgroup configuration checks
make the base/controller functions return successfully if cgroups v1/v2
are not configured in the kernel
2018-02-23 15:07:04 -06:00
William Hubbs
aa7d3a7911 openrc: force deptree update for sysinit runlevel 2018-02-22 16:16:07 -06:00
William Hubbs
98262647a9 supervise-daemon: zero out the cmdline buffer when it is allocated 2018-02-22 12:54:21 -06:00
William Hubbs
5868abe97b start-stop-daemon: compiler warning cleanup 2018-02-21 18:16:56 -06:00
William Hubbs
71aad16256 openrc-run: clean up a compiler warning 2018-02-21 18:15:35 -06:00
William Hubbs
e275da84de supervise-daemon: remove references to PATH_MAX 2018-02-21 18:14:56 -06:00
William Hubbs
a6cc7f06cf rc.c: remove PATH_MAX references 2018-02-21 13:49:41 -06:00
William Hubbs
c1178c8eeb rc-selinux.c: remove references to path_max 2018-02-20 16:35:50 -06:00
William Hubbs
3c031ca978 rc-plubin.c: remove references to PATH_MAX 2018-02-20 16:01:15 -06:00
William Hubbs
8e02406d8f rc-misc.c: remove references to PATH_MAX 2018-02-20 14:22:29 -06:00
William Hubbs
8dbdabcc5e start-stop-daemon: clean up string handling 2018-02-16 14:04:40 -06:00
William Hubbs
488d8989c5 openrc-run: clean up string handling
- remove references to PATH_MAX
- use xasprintf to create strings
2018-02-15 15:26:40 -06:00
William Hubbs
9e14b35da8 rc-update: remove reference to PATH_MAX 2018-02-15 12:23:39 -06:00
William Hubbs
7b4879cb72 mountinfo: create strings with xasprintf 2018-02-14 16:56:19 -06:00
William Hubbs
74cfb455c5 kill_all: create strings with xasprintf 2018-02-14 16:50:24 -06:00
William Hubbs
0110487722 helpers.h: silence compiler warnings about xasprintf 2018-02-10 16:48:22 -06:00
William Hubbs
68b9b0bc2a xasprintf: exit if return value of vsnprintf is invalid 2018-02-10 14:49:40 -06:00
William Hubbs
4616f8f809 helpers.h: add xasprintf function
This is our own version of asprintf(). This original code was written by
Mike Frysinger, and I was able to modify it to use our memory helper
functions.

We need a version of this code because it is not available on glibc at
least without defining _GNU_SOURCE, and I would rather not do that.

This is the first step in improving string handling in OpenRC for #207.
2018-02-09 16:27:12 -06:00
William Hubbs
287d71bd25 helpers.h: style fix 2018-02-09 15:35:12 -06:00
Michael Orlitzky
c1ffe4d9f2 man/openrc-run.8: fix mountinfo args.
The "Ar" tag for the mountinfo command contained a typo (leading
space) that resulted in the tag being output verbatim; that is,

  mountinfo ... .Ar mount1 mount2

rather than e.g.

  mountinfo ... <mount1> <mount2>

This commit deletes the leading space to fix the output.

This fixes #204.
2018-02-06 13:53:11 -06:00
Michael Orlitzky
4c517bdb2b man/openrc-run.8: add missing "Xo" tags for fstabinfo and mountinfo.
The BUILTINS are all surrounded by Xo...Xc tags, but the opening "Xo"
was missing from the two commands fstabinfo and mountinfo. This commit
adds them, and thereby fixes the spacing when viewed by man.

This is for #204.
2018-02-06 13:52:36 -06:00
William Hubbs
110582491f service-script-guide.md cleanups
Refer to /var/run in the documentation instead of /run, and make it
clear at the top of the pidfile section that we use /run under Linux.

This is for #202.
2018-01-24 17:43:08 -06:00
William Hubbs
5dd1d39d20 typo fix 2018-01-24 10:56:33 -06:00
William Hubbs
1771bc2a83 checkpath: use fchown and fchmod to handle ownership and mode changes
This is related to #195.

This is an attempt to shorten the window for the first two issues
discussed by using a file descriptor which does not follow symbolic
links and using the fchmod and fchown calls instead of chown and chmod.
with.
2018-01-23 16:56:06 -06:00
William Hubbs
87c98ebb01 checkpath: fix lchown error message
X-Gentoo-Bug: 643084
X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=643084
2018-01-16 13:34:37 -06:00
William Hubbs
4af5a80b0c _rc_deptree_load - return NULL if the stat() call is not successful
X-Gentoo-Bug: 643084
X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=643084
2018-01-16 13:11:22 -06:00
William Hubbs
fee2ffe559 Reformat and fix titles in documentation 2018-01-12 14:10:42 -06:00
William Hubbs
8878f8916b Rename guide.md to user-guide.md to better describe its purpose 2018-01-11 10:57:05 -06:00
William Hubbs
14e3359a9e move developer documentation from guide.md to service-script-guide.md 2018-01-10 13:25:13 -06:00
William Hubbs
918d955fd2 checkpath: use lchown instead of chown
Checkpath should never follow symbolic links when changing ownership of a file.

This is for https://github.com/openrc/openrc/issues/195.
2018-01-09 17:25:28 -06:00
William Hubbs
92cfa0e543 service-script-guide.md: formatting changes
Add a title, adjust the headings and update the example that referred to
"net.lo" to refer to "loopback".
2018-01-08 15:33:03 -06:00
Michael Orlitzky
c2bd33e483 service-script-guide.md: new guide for service script authors.
This fixes #162.
2018-01-08 13:59:12 -06:00
3PO
f42ec82f21 net-online: only process symbolic links in /sys/class/net
The /sys/class/net directory contains files which are not symlinks if
the system has bonded devices [1].  We should ignore these files.

This fixes #196.

[1] https://elkano.org/blog/manage-interface-bondings-sysfs-interface/
2018-01-05 14:56:33 -06:00
William Hubbs
7affff568a init.d.examples: pid files always go in /var
This removes the @VARBASE@ substitution since it is always translated to
/var.
2017-12-20 11:01:29 -06:00
William Hubbs
4f750933fd procfs: remove the @sysconfdir@ reference 2017-12-14 17:31:57 -06:00
William Hubbs
50b69d564a hostname: replace @SYSCONFDIR@ references with /etc
I do not know of any situation where /etc/hostname is at any other
location. Also, this does not run on prefix.
2017-12-14 17:07:31 -06:00
William Hubbs
eb18f4f348 hwclock: use shell variables for configuration file path
This removes a reference to @SYSCONFDIR@.
2017-12-14 16:38:09 -06:00
William Hubbs
d5f3fe52c8 sysctl: hard code paths for sysctl files on *bsd
For *BSD,the sysctl*.conf files are always in /etc.
2017-12-14 14:18:39 -06:00
William Hubbs
bb1bc6eeb7 local: misc cleanups
Remove references to @SYSCONFDIR@ since these can be calculated at
runtime.
Also style fixes.
2017-12-14 12:52:03 -06:00
William Hubbs
53844fd0dc devfs: cleanup
clean up local definitions. Also remove @SYSCONFDIR@ substitutions since
they can be calculated at runtime.
2017-12-14 12:08:38 -06:00
bell07
14938c29ce net-online: wait for ping_test_host
The script should wait till the ping host is available or timeout reached
Closes : #179
Closes : #191
2017-12-12 16:29:34 -06:00
William Hubbs
8bf501aaf2 network: use 'command -v ip' to test for the ip executable
This is an improved test because it doesn't require the ip executable to be
in a specific path.
2017-12-12 14:23:04 -06:00
William Hubbs
9d05f68b51 Do not use file tests in net-online
https://unix.stackexchange.com/questions/252002/help-testing-special-file-in-sys-class-net

This is for #189
2017-12-12 12:45:52 -06:00
William Hubbs
ee2524cd1d net-online: clean up quoting and test for existence
This is for #178.
2017-12-11 17:41:04 -06:00
Marcel Greter
5c81661d47 Gracefully handle unreadable /sys/class/net/dev/ nodes
Fixes https://bugs.gentoo.org/629228
Fixes #189
Fixes #185
Fixes #178
2017-12-11 14:46:16 -06:00
William Hubbs
fb96c9c127 Make bash-completion and zsh-completion optional 2017-12-07 12:53:04 -06:00
William Hubbs
6c456f9383 Add zsh-completion support 2017-12-07 11:30:32 -06:00
William Hubbs
d220fc2723 add bash completion support
This fixes #188.
2017-12-06 13:25:26 -06:00
William Hubbs
a2447dfb42 rc-service: add --ifcrashed option
This works like the other --if options. If the service is crashed, run
the command.

This fixes #154.
2017-12-04 17:17:17 -06:00
William Hubbs
cee3919908 Clean up the calls to group_add_service
This function should only be called once and it does not take any
arguments.

X-Gentoo-Bug: 639166
X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=639166
2017-12-01 15:43:09 -06:00
William Hubbs
0feadd2922 man/openrc-run.8: update documentation for command_user 2017-11-30 16:00:42 -06:00
Will Miles
a7c99506d9 Fix repeated dependency cache rebuild if clock skewed
rc_deptree_update_needed would return early as soon as it found
any file newer than the existing dependency cache.  Unfortunately,
the first file found may not be the newest one there; so the
clock skew workaround in rc-misc:_rc_deptree_load would be given
a timestamp that was still too old.

This fix forces a full scan of all relevant files, so as to
ensure that we return a timestamp that will allow the clock skew
fix to operate.   The runtime cost is no worse than the case where
the cache is up to date (ie. we must check every possible file).

This fixes #161.
2017-11-30 13:56:54 -06:00
Julien Reichardt
f012930775 man/openrc-run.8: remove white space
This is for #184.
2017-11-29 15:06:06 -06:00
Julien Reichardt
ddbdb69658 add more variables for start-stop-daemon and supervise-daemon options
Add the following variables to expose more arguments that can be passed
to start-stop-daemon or supervise-daemon:

- directory will be passed to --chdir
- error_log will be passed to --stderr
- output_log will be passed to --stdout
- umask will be passed to umask

This is for #184.
2017-11-29 15:06:06 -06:00
Doug Freed
c84ebb94d1 start-stop-daemon: properly handle missing pidfile
X-Gentoo-Bug: 639218
X-Gentoo-Bug-URL: https://bugs.gentoo.org/639218
2017-11-29 15:10:39 -05:00
William Hubbs
3de6395ae3 split cgroups mounting out of sysfs
This is neceessary to allow cgroups to be mounted in an lxc/lxd
container.

Fixes https://github.com/openrc/openrc/issues/187
2017-11-28 17:14:33 -06:00
William Hubbs
6bb7ebec48 fix FreeBSD build
This is for #186.
2017-11-27 11:10:00 -06:00
Doug Freed
a192caf88f rc-schedules: if given nothing to look for, stop
This avoids trying to kill everything.

X-Gentoo-Bug: 631958
X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=631958
2017-11-19 11:05:30 -05:00
William Hubbs
e805c74d31 s6 supervisor fixes
Add the ability to force-kill a service if it does not go down
successfully. Also, adjust the default wait time for an s6 service to go
down to 60 seconds.
2017-11-16 15:35:35 -06:00
William Hubbs
318e873481 strongly encourage Linux users to not make /etc/mtab a flat file
The OpenRC team does not currently know of any modern linux tools that
require /etc/mtab to be a flat file, so this puts users on notice that
the mtab service will be removed in the future.
2017-11-14 15:41:03 -06:00
William Hubbs
0d15898f58 adjust mtab and localmount dependencies
localmount had mtab in its "use" dependencies; however, it makes more
sense to add "before localmount" to the mtab service and remove
"use mtab" from the localmount service.
2017-11-14 13:20:49 -06:00
William Hubbs
971e82784c rc_find_pids: namespace fix
Ignore namespaces if there are errors reading either the pid namespace
for the current process or the process we aare testing.

This fixes https://github.com/openrc/openrc/issues/180.
2017-11-13 16:54:57 -06:00
William Hubbs
90d9ea656f start-stop-daemon: do not use do_stop to verify whether a daemon is running
X-Gentoo-Bug: 636574
X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=636574
2017-11-07 15:30:34 -06:00
William Hubbs
a3d1c8a0e7 fix issue with --reexec call 2017-10-30 18:21:39 -05:00
William Hubbs
913b2ca537 supervise-daemon: use RC_SVCNAME as the first argument to the daemon
This makes ps show which service the supervisor is monitoring.
2017-10-27 19:22:09 -05:00
William Hubbs
3fe99c8b82 supervise-daemon: fix logging for reexec and the child command line 2017-10-27 17:34:29 -05:00
William Hubbs
27b8183de2 log as supervise-daemon not the service 2017-10-27 15:33:47 -05:00
William Hubbs
f32d8e1bfe supervise-daemon: clarify a log message 2017-10-26 17:01:17 -05:00
William Hubbs
d019f34a83 supervise-daemon: log the command line we run to spawn the child process 2017-10-26 13:57:04 -05:00
William Hubbs
bb9c481f02 supervise-daemon: log with the service name instead of "supervise-daemon" 2017-10-26 13:36:41 -05:00
William Hubbs
82da844b42 implement "unsupervised" status
The unsupervised status is to be used when a supervisor of a supervised
service dies but leaves the service daemon itself running.
2017-10-26 13:11:12 -05:00
William Hubbs
667a09983c supervise-daemon: remove child_pid from saved options during shutdown
This allows us to detect when the supervisor dies unexpectedly because
in that case child_pid will still exist.
2017-10-26 12:58:59 -05:00
William Hubbs
cf429ee359 rc_service_value_set: remove the option if NULL is the value
This allows the equivalent of "unsetting" a value for a service.
2017-10-26 12:54:37 -05:00
William Hubbs
6f3e2e2d7d supervise-daemon.sh: fix status function with no namespaces 2017-10-25 21:20:15 -05:00
Patrick McLean
35b88fb42b cgroups_cleanup: clean up shutdown signaling
- do not sleep for the full 90 seconds if processes are dead
- re-arrange the order of signals we attempt to send to the processes
2017-10-25 21:19:15 -05:00
William Hubbs
a428c325a9 add "unsupervised" status and return code 64 to supervise-daemon status function
This is to be used if the service is being supervised and the
supervisor is somehow killed.

Currently, this is very linux specific, but I will expand to other
platforms, patches are welcome.
2017-10-25 15:09:42 -05:00
William Hubbs
3219ecd608 supervise-daemon: fix build issue for >=glibc-2.26
X-Gentoo-Bug: 635334
X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=635334
2017-10-24 16:47:53 -05:00
William Hubbs
0d8dc4f798 version 0.35 2017-10-24 16:46:52 -05:00
William Hubbs
f3c70bf5b5 Update ChangeLog 2017-10-24 10:42:11 -05:00
William Hubbs
f5acc66db7 rc_find_pids: ignore pids that are not in our pid namespace
X-Gentoo-Bug: 634634
X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=634634
2017-10-24 10:37:37 -05:00
William Hubbs
fdce4769f2 supervise-daemon: multiple fixes
- Harden against dying by handling all signals that would terminate the
program and adding --reexec support
- factor the supervisor into its own function
- fix test for whether we are already running
2017-10-24 10:26:18 -05:00
William Hubbs
35b1996704 supervise-daemon: elevate some log messages to warnings
Prior to this change, we were logging unexpected terminations of daemons
we were supervising at the info level. This change moves the logs to
warnings.
2017-10-18 18:07:50 -05:00
William Hubbs
3c8e7ed255 version 0.34 2017-10-13 16:10:57 -05:00
William Hubbs
acaed1f910 Update ChangeLog 2017-10-13 11:29:49 -05:00
William Hubbs
91109e31d8 update news 2017-10-12 18:54:17 -05:00
William Hubbs
2b6eeea01d man: remove service(8) man page 2017-10-12 18:47:36 -05:00
William Hubbs
a15de23e57 typo fix 2017-10-10 10:56:27 -05:00
William Hubbs
efa9ba485d init.d/sysfs.in: fix reference to RC_LIBEXECDIR
The sysfs init script referred to @LIBEXECDIR@ before this change, but
it is better to refer to RC_LIBEXECDIR so that we get rid of a sed
substitution.
2017-10-09 15:54:06 -05:00
d4ddd72701 add option to make agetty startup quiet
This fixes #150
2017-10-06 14:43:59 -05:00
William Hubbs
1e9af2cd42 fix compiler warning 2017-10-05 18:31:07 -05:00
William Hubbs
3c05db74f6 remove service binary
The service binary was just a synonym for rc-service, so use rc-service
instead of service. If you want a "service" binary, it should be
something that can determine which service manager you are running and
run the appropriate service manager commands.
2017-10-02 18:09:09 -05:00
William Hubbs
edc54b0377 version 0.33 2017-10-02 16:58:59 -05:00
William Hubbs
8e53a3fa8a Update ChangeLog 2017-10-02 11:21:29 -05:00
William Hubbs
7f3b413111 use printf consistently in cgroups handling
This makes the cgroups handling consistent between cgroups v1 and v2.
Also, it fixes #167.
2017-09-29 12:51:12 -05:00
William Hubbs
1ccba05658 sh/rc-functions.sh: add need_if_exists convenience function 2017-09-22 17:22:50 -05:00
William Hubbs
c46adf1434 man/openrc-run.8: Clarify the explanation of the need dependency 2017-09-22 16:24:20 -05:00
William Hubbs
1cac8b080c ignore sigchld when shutting down the supervised process
We need to do this to skip the zombie state for the child process since
we are not easily able to wait() for it.
2017-09-18 16:59:18 -05:00
William Hubbs
b58194ef63 typo fix 2017-09-18 13:30:56 -05:00
William Hubbs
b28c0d6f66 typo fix 2017-09-18 13:03:34 -05:00
William Hubbs
3cf19b0f30 supervise-daemon: code cleanup
Clean up the process for killing an active supervisor when stopping.
2017-09-18 12:25:37 -05:00
William Hubbs
0eb47b9af3 initialize the stop schedule 2017-09-18 10:36:17 -05:00
William Hubbs
4ab60ff109 rc-schedules.c: pass the correct pid to rc_find_pids
This is for #163.
2017-09-17 14:20:05 -05:00
Jason Zaman
db4a578273 selinux: fix const qualifier warning
rc-selinux.c: In function ‘selinux_setup’:
rc-selinux.c:361:9: warning: assignment discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
  curr_t = context_type_get(curr_con);
         ^
2017-09-17 11:41:24 -05:00
Jason Zaman
b1c3422f45 selinux: use openrc contexts path to get contexts
The minimum requirement for libselinux is now >=2.6
The refpolicy and the gentoo policy contain the
contexts since version 2.20170204-r4
2017-09-17 11:40:07 -05:00
William Hubbs
3fafd7a76e sysfs: fix cgroup hybrid mode
In hybrid mode, we should not try to mount cgroup2 if it is not
available in the kernel.

This fixes #164.
2017-09-16 17:02:52 -05:00
William Hubbs
cd5722aca5 cgroup2_find_path: use legacy mode if cgroup2 is not in the kernel
This is related to #164.
2017-09-16 16:49:22 -05:00
William Hubbs
dcb4a4d261 version 0.32 2017-09-16 13:24:52 -05:00
124 changed files with 4421 additions and 2423 deletions

View File

@@ -1,4 +1,5 @@
# Using Busybox as your Default Shell with OpenRC
Using Busybox as your Default Shell with OpenRC
===============================================
If you have/bin/sh linked to busybox, you need to be aware of several
incompatibilities between busybox's applets and the standalone

2459
ChangeLog

File diff suppressed because it is too large Load Diff

View File

@@ -1,11 +1,12 @@
# Features Scheduled for Removal
Features Scheduled for Removal
==============================
The following is a list of files and features that are going to be removed in
the source tree. Every entry should contain what exactly is going away, why it
is happening, and who is going to be doing the work. When the feature is
removed, it should also be removed from this file.
## Service pause action
# Service pause action
When: 1.0
@@ -13,7 +14,7 @@ Why: The same affect can be obtained with the --nodeps option to stop.
Who:
## start-stop-daemon options --startas, --chuid , --oknodo
# start-stop-daemon options --startas, --chuid , --oknodo
When: 1.0
@@ -25,7 +26,7 @@ Why: Obsolete or replaced by other options.
Who:
## runscript and rc symbolic links
# runscript and rc symbolic links
When: 1.0
@@ -34,7 +35,7 @@ Why: Deprecated in favor of openrc-run and openrc due to naming
Who:
## support for the opts variable in service scripts
# support for the opts variable in service scripts
When: 1.0
@@ -43,7 +44,7 @@ Why: Deprecated in favor of extra_commands, extra_started_commands
Who:
## support for local_start and local_stop
# support for local_start and local_stop
When: 1.0
@@ -51,7 +52,7 @@ Why: Deprecated in favor of executable scripts in @SYSCONFDIR@/local.d
Who:
## the mtab service script
# the mtab service script
When: force /etc/mtab to link to /proc/self/mounts in 1.0, remove
service in 2.0
@@ -61,13 +62,13 @@ Why: /etc/mtab should be a symbolic link to /proc/self/mounts on modern
Who:
## C API Functions in rc.h
# C API Functions in rc.h
If you have a c program that links to librc and uses functions from
there, this section will list API functions which are deprecated and
will be removed along with the reason they are being removed.
### rc_getline()
## rc_getline()
When: 1.0

View File

@@ -1,4 +1,5 @@
# OpenRC History
OpenRC History
==============
This history of OpenRC was written by Daniel Robbins, Roy Marples, William
Hubbs and others.

View File

@@ -15,12 +15,24 @@ include ${TOP}/Makefile.inc
SUBDIR= conf.d etc init.d local.d man scripts sh src support sysctl.d
# Build bash completion or not
MKBASHCOMP?= no
ifeq (${MKBASHCOMP},yes)
SUBDIR+= bash-completion
endif
# Build pkgconfig or not
MKPKGCONFIG?= yes
ifeq (${MKPKGCONFIG},yes)
SUBDIR+= pkgconfig
endif
# Build zsh completion or not
MKZSHCOMP?= no
ifeq (${MKZSHCOMP},yes)
SUBDIR+= zsh-completion
endif
# We need to ensure that runlevels is done last
SUBDIR+= runlevels

View File

@@ -1,3 +1,3 @@
NAME= openrc
VERSION= 0.31.2
VERSION= 0.39
PKG= ${NAME}-${VERSION}

95
NEWS.md
View File

@@ -1,8 +1,101 @@
# OpenRC NEWS
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.39
This version removes the support for addons.
The only place I know that this was used was Gentoo Baselayout 1.x, so
it shouldn't affect anyone since baselayout-1 has been dead for a few
years.
Since all supported Linux kernel versions now make efivarfs immutable
and all of the tools that access efivarfs are aware of this, we no
longer mount efivarfs read-only. See the following github issue for more
information:
https://github.com/openrc/openrc/issues/238
This version adds timed shutdown and cancelation of shutdown to
openrc-shutdown. Shutdowns can now be delayed for a certain amount of
time or scheduled for an exact time.
supervise-daemon supports health checks, which are a periodic way to make sure a
service is healthy. For more information on setting this up, please see
supervise-daemon-guide.md.
The --first-time switch has been added to all modprobe commands in the
modules service. This means that, on Linux, you will see failures if a
module was loaded by an initramfs or device manager before this service
runs. These messages are harmless, but to clean them up, you should adjust your
modules autoload configuration.
## OpenRC 0.37
start-stop-daemon now supports logging stdout and stderr of daemons to
processes instead of files. These processes are defined by the
output_logger and error_logger variables in standard service scripts, or
by the -3/--output-logger or -4/--error-logger switches if you use
start-stop-daemon directly. For more information on this, see the
start-stop-daemon man page.
## OpenRC 0.36
In this release, the modules-load service has been combined into the
modules service since there is no reason I know of to keep them
separate. However, modules also provides modules-load in case you were
using modules-load in your dependencies.
The consolefont, keymaps, numlock and procfs service scripts no longer
have a dependency on localmount.
If you are a linux user and are still separaating / from /usr,
you will need to add the following line to the appropriate conf.d files:
rc_need="localmount"
## OpenRC 0.35
In this version, the cgroups mounting logic has been moved from the
sysfs service to the cgroups service. This was done so cgroups can be
mounted inside an lxc/lxd container without using the other parts of the
sysfs service.
?As a result of this change, if you are upgrading, you need to add
cgroups to your sysinit runlevel by running the following command as
root:
```
# rc-update add cgroups sysinit
```
For more information, see the following issue:
https://github.com/openrc/openrc/issues/187
Consider this your second notification with regard to /etc/mtab being a
file instead of a symbolic link.
In this version, the mtab service will complain loudly if you have
mtab_is_file set to yes and recommend that you change this to no and
restart the mtab service to migrate /etc/mtab to a symbolic link.
If there is a valid technical reason to keep /etc/mtab as a flat file
instead of a symbolic link to /proc/self/mounts, we are interested and
we will keep the support in that case. Please open an issue and let us
know however. Otherwise, consider this your final notice that the mtab
service will be removed in the future.
## OpenRC 0.33
This version removes the "service" binary which was just a copy of
"rc-service" provided for compatibility.
If you still need the "service" binary, as opposed to "rc-service", it is
recommended that you use something like Debian's init-system-helpers.
Otherwise, just use "rc-service" in place of "service".
## OpenRC 0.31
This version adds support for Control Groups version 2, which is

View File

@@ -1,4 +1,5 @@
# OpenRC README
OpenRC README
=============
OpenRC is a dependency-based init system that works with the
system-provided init program, normally `/sbin/init`. Currently, it does
@@ -22,6 +23,7 @@ below arguments to the make command
PROGLDFLAGS=-static
LIBNAME=lib64
DESTDIR=/tmp/openrc-image
MKBASHCOMP=no
MKNET=no
MKPAM=pam
MKPREFIX=yes
@@ -31,6 +33,7 @@ MKSTATICLIBS=no
MKSYSVINIT=yes
MKTERMCAP=ncurses
MKTERMCAP=termcap
MKZSHCOMP=no
PKG_PREFIX=/usr/pkg
LOCAL_PREFIX=/usr/local
PREFIX=/usr/local

View File

@@ -1,4 +1,5 @@
# OpenRC Style Guide
OpenRC Coding Style Guide
=========================
This is the openrc style manual. It governs the coding style of all code
in this repository. Follow it. Contact openrc@gentoo.org for any questions

View File

@@ -1,4 +1,5 @@
# Setting up the agetty service in OpenRC
Setting up the agetty service in OpenRC
=================================xxxxxx
The agetty service is an OpenRC specific way to monitor and respawn a
getty, using agetty, on Linux. To use this method, make sure you aren't

11
bash-completion/Makefile Normal file
View File

@@ -0,0 +1,11 @@
DIR= ${BASHCOMPDIR}
CONF= openrc \
openrc-service-script \
rc-service \
rc-status \
rc-update \
MK= ../mk
include ${MK}/os.mk
include ${MK}/scripts.mk

24
bash-completion/openrc Normal file
View File

@@ -0,0 +1,24 @@
# Copyright (c) 2017 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.
#
# openrc completion command
#
_openrc()
{
local cur
COMPREPLY=()
cur="${COMP_WORDS[COMP_CWORD]}"
if [[ ${#COMP_WORDS[*]} -le 2 ]]; then
COMPREPLY=($(compgen -W "$(rc-status --list)" -- $cur))
fi
return 0
} &&
complete -F _openrc openrc

View File

@@ -0,0 +1,29 @@
# Copyright (c) 2017 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.
_openrc_service_script()
{
local script="${COMP_WORDS[0]}"
local cur="${COMP_WORDS[$COMP_CWORD]}"
if [[ ( -f "${script}" || -h "${script}" ) && -r "${script}" ]] \
&& [[ "$(head -n 1 "${script}")" =~ \#\!.*/openrc-run ]]
then
[[ $COMP_CWORD -gt 1 ]] && return 1
COMPREPLY=($(opts="start stop status restart pause zap ineed needsme iuse usesme broken"; \
eval "$(grep '^opts=' "${script}")"; echo "${opts}"))
[[ -n "$COMPREPLY" ]] || COMPREPLY=(start stop restart zap)
COMPREPLY=($(compgen -W "${COMPREPLY[*]}" -- "${cur}"))
else
COMPREPLY=($(compgen -o default -- "${cur}"))
fi
return 0
}
complete -F _openrc_service_script */etc/init.d/*

113
bash-completion/rc-service Normal file
View File

@@ -0,0 +1,113 @@
# Copyright (c) 2017 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.
#
# rc-service completion command
#
_rc_service()
{
local cur prev numwords opts
local words i x filename
local action actionpos
COMPREPLY=()
cur="${COMP_WORDS[COMP_CWORD]}"
prev="${COMP_WORDS[COMP_CWORD-1]}"
numwords=${#COMP_WORDS[*]}
if [[ ${prev} == '>' || ${prev} == '<' ]] ; then
COMPREPLY=($(compgen -f -- ${cur}))
return 0
fi
# find action
for x in ${COMP_LINE} ; do
if [[ ${x} =~ --(list|exists|resolve) ]] || [[ ${x} =~ -(l|e|r) ]]
then
action=${x}
break
fi
done
if [[ -n ${action} ]]; then
for ((i = 0; i < ${numwords}; i++ )); do
if [[ ${COMP_WORDS[${i}]} == "${action}" ]]; then
actionpos=${i}
break
fi
done
for ((i = 1; i < ${numwords}; i++ )); do
if [[ ! ${COMP_WORDS[$i]} == -* ]]; then
break
fi
done
fi
if [[ ${COMP_CWORD} -eq 3 ]]; then
return 1
fi
# check if an option was typed
if [[ ${cur} == -* ]]; then
if [[ ${cur} == --* ]]; then
opts="--list --exists --resolve"
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
return 0
elif [[ ${cur} == -* ]]; then
opts="-l -e -r"
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
return 0
fi
# NOTE: This slows things down!
# (Adapted from bash_completion by Ian Macdonald <ian@caliban.org>)
# This removes any options from the list of completions that have
# already been specified on the command line.
COMPREPLY=($(echo "${COMP_WORDS[@]}" | \
(while read -d ' ' i; do
[[ -z ${i} ]] && continue
# flatten array with spaces on either side,
# otherwise we cannot grep on word boundaries of
# first and last word
COMPREPLY=" ${COMPREPLY[@]} "
# remove word from list of completions
COMPREPLY=(${COMPREPLY/ ${i%% *} / })
done
echo ${COMPREPLY[@]})))
return 0
else
# no option was typed
if [[ ${COMP_CWORD} -eq 1 ]]; then # if first word typed
words="$(rc-service --list | grep ^${cur})" # complete for init scripts
COMPREPLY=($(for i in ${words} ; do \
[[ ${i} == ${cur}* ]] && echo ${i} ; \
done))
return 0
elif [[ ${COMP_CWORD} -eq 2 ]] && [[ ${prev} != -* ]]; then # if second word typed and we didn't type in a function
filename=$(rc-service --resolve ${prev})
opts=$(cat ${filename} | grep "^\w*()" | sed "s/().*$//") # Greps the functions included in the init script
if [[ "x${opts}" == "x" ]] ; then # if no options found loosen the grep algorhythm
opts=$(cat ${filename} | grep "\w*()" | sed "s/().*$//")
fi
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
return 0
fi
fi
if [[ ${action} == '--exists' ]] || [[ ${action} == '-e' ]] || \
[[ ${action} == '--resolve' ]] || [[ ${action} == '-r' ]]; then
words="$(rc-service --list | grep ^${cur})"
COMPREPLY=($(for i in ${words} ; do \
[[ ${i} == ${cur}* ]] && echo ${i} ; \
done))
return 0
fi
return 0
} &&
complete -F _rc_service rc-service

31
bash-completion/rc-status Normal file
View File

@@ -0,0 +1,31 @@
# Copyright (c) 2017 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.
#
# rc-status completion command
#
_rcstatus()
{
local cur
cur="${COMP_WORDS[COMP_CWORD]}"
if [[ $COMP_CWORD -eq 1 ]]; then
if [[ "${cur}" == --* ]]; then
COMPREPLY=($(compgen -W '--all --list --unused' -- ${cur}))
elif [[ "${cur}" == -* ]]; then
COMPREPLY=($(compgen -W '-a -l -u' -- ${cur}))
else
COMPREPLY=($(compgen -W "$(rc-status --list)" -- ${cur}))
fi
else
unset COMPREPLY
fi
return 0
} &&
complete -F _rcstatus rc-status

42
bash-completion/rc-update Normal file
View File

@@ -0,0 +1,42 @@
# Copyright (c) 2017 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.
#
# rc-update completion command
#
_rc_update()
{
local cur show
COMPREPLY=()
cur="${COMP_WORDS[COMP_CWORD]}"
if [[ $COMP_CWORD -eq 1 ]]; then
if [[ "${cur}" == -* ]]; then
COMPREPLY=($(compgen -W '-a -d -s' -- ${cur}))
else
COMPREPLY=($(compgen -W 'add del show' ${cur}))
fi
else
if [[ "${COMP_WORDS[1]}" == "show" ]] || [[ "${COMP_WORDS[1]}" == "-s" ]]; then
show="TRUE"
fi
if ([[ $COMP_CWORD -eq 3 ]] && [[ -z "$show" ]]) || \
([[ $COMP_CWORD -eq 2 ]] && [[ -n "$show" ]]); then
COMPREPLY=($(compgen -W "$(rc-status --list)" -- $cur))
elif [[ $COMP_CWORD -eq 2 ]]; then
COMPREPLY=($(compgen -W "$(rc-service --list)" $cur))
elif [[ ${#COMP_WORDS[*]} -gt 2 ]] ; then
COMPREPLY=($(compgen -W "$(rc-status --list)" -- $cur))
else
unset COMPREPLY
fi
fi
return 0
} &&
complete -F _rc_update rc-update

View File

@@ -1,3 +1,6 @@
# make agetty quiet
#quiet="yes"
# Set the baud rate of the terminal line
#baud=""

View File

@@ -8,11 +8,6 @@
#modules_2="ipv6"
#modules="ohci1394"
# Linux users can give modules a different name when they load - the new name
# will also be used to pick arguments below.
# This is not supported on FreeBSD.
#modules="dummy:dummy1"
# Linux users can give the modules some arguments if needed, per version
# if necessary.
# Again, the most specific versioned variable will take precedence.

View File

@@ -1,5 +1,13 @@
# As far as we are aware, there are no modern linux tools or use cases
# which require /etc/mtab to be a separate file from /proc/self/mounts,
# so this setting should be commented out.
# If it is set to yes, please comment it out and run this command:
# # rc-service mtab restart
# In the future, the mtab service will be removed since we are not aware
# of any need to manipulate /etc/mtab as a separate file from
# /proc/self/mounts.
# If you have a technical reason we should keep this support, please
# open an issue at https://github.com/openrc/openrc/issues and let us
# know about your situation.
# This setting controls whether /etc/mtab is a file or symbolic link.
# Most of the time, you shouldn't touch this. However, if the default
# breaks your system in some way, please see the NEWS.md file that comes
# with OpenRC for the actions to take.
# mtab_is_file=no

View File

@@ -227,6 +227,11 @@ rc_tty_number=12
# /sys/fs/cgroup in hybrid or legacy mode.
#rc_controller_cgroups="YES"
# The following setting turns on the memory.use_hierarchy setting in the
# root memory cgroup for cgroups v1.
# It must be set to yes in this file if you want this functionality.
#rc_cggroup_memory_use_hierarchy="NO"
# The following settings allow you to set up values for the cgroups version 1
# controllers for your services.
# They can be set in this file;, however, if you do this, the settings

1
init.d/.gitignore vendored
View File

@@ -1,5 +1,6 @@
agetty
binfmt
cgroups
modules-load
bootmisc
fsck

View File

@@ -19,11 +19,12 @@ SRCS-FreeBSD= hostid.in modules.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 \
modules-load.in mixer.in nscd.in powerd.in syscons.in
mixer.in nscd.in powerd.in syscons.in
SRCS-Linux= agetty.in binfmt.in devfs.in dmesg.in hwclock.in consolefont.in \
keymaps.in killprocs.in modules.in modules-load.in mount-ro.in mtab.in \
numlock.in procfs.in net-online.in sysfs.in termencoding.in
SRCS-Linux= agetty.in binfmt.in devfs.in cgroups.in dmesg.in hwclock.in \
consolefont.in keymaps.in killprocs.in modules.in \
mount-ro.in mtab.in numlock.in procfs.in net-online.in sysfs.in \
termencoding.in
# Generic BSD scripts
SRCS-NetBSD= hostid.in moused.in newsyslog.in pf.in rarpd.in rc-enabled.in \

View File

@@ -28,5 +28,12 @@ start_pre() {
eerror "symbolic links to it for the ports you want to start"
eerror "agetty on and add those to the appropriate runlevels."
return 1
else
export EINFO_QUIET="${quiet:-yes}"
fi
}
stop_pre()
{
export EINFO_QUIET="${quiet:-yes}"
}

149
init.d/cgroups.in Normal file
View File

@@ -0,0 +1,149 @@
#!@SBINDIR@/openrc-run
# Copyright (c) 2017 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="Mount the control groups."
cgroup_opts=nodev,noexec,nosuid
depend()
{
keyword -docker -prefix -systemd-nspawn -vserver
after sysfs
}
cgroup1_base()
{
grep -qw cgroup /proc/filesystems || return 0
if ! mountinfo -q /sys/fs/cgroup; then
ebegin "Mounting cgroup filesystem"
local opts="${cgroup_opts},mode=755,size=${rc_cgroupsize:-10m}"
mount -n -t tmpfs -o "${opts}" cgroup_root /sys/fs/cgroup
eend $?
fi
if ! mountinfo -q /sys/fs/cgroup/openrc; then
local agent="${RC_LIBEXECDIR}/sh/cgroup-release-agent.sh"
mkdir /sys/fs/cgroup/openrc
mount -n -t cgroup \
-o none,${cgroup_opts},name=openrc,release_agent="$agent" \
openrc /sys/fs/cgroup/openrc
printf 1 > /sys/fs/cgroup/openrc/notify_on_release
fi
return 0
}
cgroup1_controllers()
{
yesno "${rc_controller_cgroups:-YES}" && [ -e /proc/cgroups ] &&
grep -qw cgroup /proc/filesystems || return 0
while read -r name _ _ enabled _; do
case "${enabled}" in
1) mountinfo -q "/sys/fs/cgroup/${name}" && continue
local x
for x in $rc_cgroup_controllers; do
[ "${name}" = "blkio" ] && [ "${x}" = "io" ] &&
continue 2
[ "${name}" = "${x}" ] &&
continue 2
done
mkdir "/sys/fs/cgroup/${name}"
mount -n -t cgroup -o "${cgroup_opts},${name}" \
"${name}" "/sys/fs/cgroup/${name}"
yesno "${rc_cgroup_memory_use_hierarchy:-no}" &&
[ "${name}" = memory ] &&
echo 1 > /sys/fs/cgroup/memory/memory.use_hierarchy
;;
esac
done < /proc/cgroups
return 0
}
cgroup2_base()
{
grep -qw cgroup2 /proc/filesystems || return 0
local base
base="$(cgroup2_find_path)"
mkdir -p "${base}"
mount -t cgroup2 none -o "${cgroup_opts},nsdelegate" "${base}" 2> /dev/null ||
mount -t cgroup2 none -o "${cgroup_opts}" "${base}"
return 0
}
cgroup2_controllers()
{
grep -qw cgroup2 /proc/filesystems || return 0
local active cgroup_path x y
cgroup_path="$(cgroup2_find_path)"
[ -z "${cgroup_path}" ] && return 0
[ -e "${cgroup_path}/cgroup.controllers" ] &&
read -r active < "${cgroup_path}/cgroup.controllers"
for x in ${rc_cgroup_controllers}; do
for y in ${active}; do
[ "$x" = "$y" ] &&
[ -e "${cgroup_path}/cgroup.subtree_control" ]&&
echo "+${x}" > "${cgroup_path}/cgroup.subtree_control"
done
done
return 0
}
cgroups_hybrid()
{
cgroup1_base
cgroup2_base
cgroup2_controllers
cgroup1_controllers
return 0
}
cgroups_legacy()
{
cgroup1_base
cgroup1_controllers
return 0
}
cgroups_unified()
{
cgroup2_base
cgroup2_controllers
return 0
}
mount_cgroups()
{
case "${rc_cgroup_mode:-hybrid}" in
hybrid) cgroups_hybrid ;;
legacy) cgroups_legacy ;;
unified) cgroups_unified ;;
esac
return 0
}
restorecon_cgroups()
{
if [ -x /sbin/restorecon ]; then
ebegin "Restoring SELinux contexts in /sys/fs/cgroup"
restorecon -rF /sys/fs/cgroup >/dev/null 2>&1
eend $?
fi
return 0
}
start()
{
# set up kernel support for cgroups
if [ -d /sys/fs/cgroup ]; then
mount_cgroups
restorecon_cgroups
fi
return 0
}

View File

@@ -13,7 +13,7 @@ description="Sets a font for the consoles."
depend()
{
need localmount termencoding
need termencoding
after hotplug bootmisc modules
keyword -docker -lxc -openvz -prefix -systemd-nspawn -uml -vserver -xenu
}

View File

@@ -20,9 +20,12 @@ depend()
mount_dev()
{
local action=--mount devfstype msg=Mounting
local action conf_d_dir devfstype msg mountopts
action=--mount
conf_d_dir="${RC_SERVICE%/*/*}/conf.d"
msg=Mounting
# Some devices require exec, Bug #92921
local mountopts="exec,nosuid,mode=0755"
mountopts="exec,nosuid,mode=0755"
if yesno ${skip_mount_dev:-no} ; then
einfo "/dev will not be mounted due to user request"
return 0
@@ -33,7 +36,7 @@ mount_dev()
msg=Remounting
fi
if fstabinfo -q /dev; then
ebegin "$msg /dev according to @SYSCONFDIR@/fstab"
ebegin "$msg /dev according to fstab"
fstabinfo -q $action /dev
eend $?
return 0
@@ -54,7 +57,7 @@ mount_dev()
ewarn "is no entry for /dev in fstab."
ewarn "This means /dev will not be mounted."
ewarn "To avoid this message, set CONFIG_DEVTMPFS or CONFIG_TMPFS to y"
ewarn "in your kernel configuration or see @SYSCONFDIR@/conf.d/devfs"
ewarn "in your kernel configuration or see ${conf_d_dir}/${RC_SVCNAME}"
fi
return 0
}

View File

@@ -20,9 +20,9 @@ depend()
start()
{
local h source x
if [ -s @SYSCONFDIR@/hostname ] && [ -r @SYSCONFDIR@/hostname ]; then
read h x <@SYSCONFDIR@/hostname
source="from @SYSCONFDIR@/hostname"
if [ -s /etc/hostname ] && [ -r /etc/hostname ]; then
read h x </etc/hostname
source="from /etc/hostname"
else
# HOSTNAME variable used to be defined in caps in conf.d/hostname.
# It is also a magic variable in bash.

View File

@@ -105,7 +105,7 @@ start()
done
[ -n "$modname" ] &&
ewarn "The $modname module needs to be configured in" \
"@SYSCONFDIR@/conf.d/modules or built in."
"${RC_SERVICE%/*/*}/conf.d/modules or built in."
fi
fi

View File

@@ -13,7 +13,7 @@ description="Applies a keymap for the consoles."
depend()
{
need localmount termencoding
need termencoding
after bootmisc clock
keyword -docker -lxc -openvz -prefix -systemd-nspawn -uml -vserver -xenu
}

View File

@@ -9,7 +9,10 @@
# This file may not be copied, modified, propagated, or distributed
# except according to the terms contained in the LICENSE file.
description="Executes user programs in @SYSCONFDIR@/local.d"
conf_d_dir="${RC_SERVICE%/*/*}/conf.d"
local_d_dir="${RC_SERVICE%/*/*}/local.d"
description="Executes user programs in ${local_d_dir}"
depend()
{
@@ -19,12 +22,12 @@ depend()
start()
{
ebegin "Starting local"
local file has_errors=0 redirect retval
local file has_errors redirect retval
has_errors=0
yesno $rc_verbose || redirect='> /dev/null 2>&1'
ebegin "Starting local"
eindent
for file in @SYSCONFDIR@/local.d/*.start; do
for file in "${local_d_dir}"/*.start; do
if [ -x "${file}" ]; then
vebegin "Executing \"${file}\""
eval "${file}" $redirect
@@ -38,32 +41,32 @@ start()
eoutdent
if command -v local_start >/dev/null 2>&1; then
ewarn "\"@SYSCONFDIR@/conf.d/local\" should be removed."
ewarn "\"${conf_d_dir}/local\" should be removed."
ewarn "Please move the code from the local_start function"
ewarn "to executable scripts with an .start extension"
ewarn "in \"@SYSCONFDIR@/local.d\""
ewarn "in \"${local_d_dir}\""
local_start
fi
eend ${has_errors}
# We have to end with a zero exit code, because a failed execution
# of an executable @SYSCONFDIR@/local.d/*.start file shouldn't result in
# of an executable ${local_d_dir}/*.start file shouldn't result in
# marking the local service as failed. Otherwise we are unable to
# execute any executable @SYSCONFDIR@/local.d/*.stop file, because a failed
# execute any executable ${local_d_dir}/*.stop file, because a failed
# marked service cannot be stopped (and the stop function would
# actually call the executable @SYSCONFDIR@/local.d/*.stop file(s)).
# actually call the executable ${local_d_dir}/*.stop file(s)).
return 0
}
stop()
{
ebegin "Stopping local"
local file has_errors=0 redirect retval
local file has_errors redirect retval
has_errors=0
yesno $rc_verbose || redirect='> /dev/null 2>&1'
ebegin "Stopping local"
eindent
for file in @SYSCONFDIR@/local.d/*.stop; do
for file in "${local_d_dir}"/*.stop; do
if [ -x "${file}" ]; then
vebegin "Executing \"${file}\""
eval "${file}" $redirect
@@ -77,16 +80,16 @@ stop()
eoutdent
if command -v local_stop >/dev/null 2>&1; then
ewarn "\"@SYSCONFDIR@/conf.d/local\" should be removed."
ewarn "\"${conf_d_dir}/local\" should be removed."
ewarn "Please move the code from the local_stop function"
ewarn "to executable scripts with an .stop extension"
ewarn "in \"@SYSCONFDIR@/local.d\""
ewarn "in \"${local_d_dir}\""
local_stop
fi
eend ${has_errors}
# An executable @SYSCONFDIR@/local.d/*.stop file which failed with a
# An executable ${local_d_dir}/*.stop file which failed with a
# non-zero exit status is not a reason to mark this service
# as failed, therefore we have to end with a zero exit code.
return 0

View File

@@ -14,7 +14,7 @@ description="Mounts disks and swap according to /etc/fstab."
depend()
{
need fsck
use lvm modules mtab root
use lvm modules root
after clock lvm modules root
keyword -docker -jail -lxc -prefix -systemd-nspawn -vserver
}

View File

@@ -1,72 +0,0 @@
#!@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 --use-blacklist -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,10 +14,66 @@ description="Loads a user defined list of kernel modules."
depend()
{
use isapnp
want modules-load
provide modules-load
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 --first-time -q --use-blacklist "$x"; rc=$? ;;
*) ;;
esac
eend $rc "Failed to load $x"
done
return 0
}
modules_load_d()
{
local x
files=$(find_modfiles)
for x in $files; do
load_modules $x
done
return 0
}
FreeBSD_modules()
{
local cnt=0 x
@@ -48,7 +104,7 @@ Linux_modules()
x=${x%.*}
done
local list= x= xx= y= args= mpargs= a=
local list= x= xx= y= args=
for x in $kv_variant_list ; do
eval list=\$modules_$(shell_var "$x")
[ -n "$list" ] && break
@@ -57,24 +113,13 @@ Linux_modules()
[ -n "$list" ] && ebegin "Loading kernel modules"
for x in $list; do
a=${x#*:}
if [ "$a" = "$x" ]; then
unset mpargs
else
x=${x%%:*}
mpargs="-o $a"
fi
aa=$(shell_var "$a")
xx=$(shell_var "$x")
for y in $kv_variant_list ; do
eval args=\$module_${aa}_args_$(shell_var "$y")
[ -n "${args}" ] && break
eval args=\$module_${xx}_args_$(shell_var "$y")
[ -n "${args}" ] && break
done
[ -z "$args" ] && eval args=\$module_${aa}_args
[ -z "$args" ] && eval args=\$module_${xx}_args
eval modprobe --use-blacklist --verbose "$mpargs" "$x" "$args"
eval modprobe --first-time --use-blacklist --verbose "$x" "$args"
done
[ -n "$list" ] && eend
}
@@ -82,7 +127,10 @@ Linux_modules()
start()
{
case "$RC_UNAME" in
FreeBSD|Linux) ${RC_UNAME}_modules ;;
FreeBSD|Linux)
modules_load_d
${RC_UNAME}_modules
;;
*) ;;
esac
return 0

View File

@@ -14,6 +14,7 @@ description="Update /etc/mtab to match what the kernel knows about"
depend()
{
after clock
before localmount
need root
keyword -prefix -systemd-nspawn
}
@@ -30,6 +31,10 @@ start()
einfo "Creating mtab symbolic link"
ln -snf /proc/self/mounts /etc/mtab
else
ewarn "The ${RC_SVCNAME} service will be removed in the future."
ewarn "Please change the mtab_is_file setting to no and run"
ewarn "# rc-service mtab restart"
ewarn "to create the mtab symbolic link."
[ -L /etc/mtab ] && ewarn "Removing /etc/mtab symbolic link"
rm -f /etc/mtab
einfo "Creating mtab file"

View File

@@ -13,7 +13,7 @@ description="Delays until the network is online or a specific timeout"
depend()
{
after modules
after modules net
need sysfs
provide network-online
keyword -docker -jail -lxc -openvz -prefix -systemd-nspawn -uml -vserver
@@ -23,6 +23,7 @@ get_interfaces()
{
local ifname iftype
for ifname in /sys/class/net/*; do
[ -h "${ifname}" ] && continue
read iftype < ${ifname}/type
[ "$iftype" = "1" ] && printf "%s " ${ifname##*/}
done
@@ -31,7 +32,7 @@ get_interfaces()
start ()
{
local carriers configured dev gateway ifcount infinite
local rc state x
local carrier operstate rc
ebegin "Checking to see if the network is online"
rc=0
@@ -44,10 +45,12 @@ start ()
ifcount=0
for dev in ${interfaces}; do
: $((ifcount += 1))
read x < /sys/class/net/$dev/carrier
[ $x -eq 1 ] && : $((carriers += 1))
read x < /sys/class/net/$dev/operstate
[ "$x" = up ] && : $((configured += 1))
read carrier < /sys/class/net/$dev/carrier 2> /dev/null ||
carrier=
[ "$carrier" = 1 ] && : $((carriers += 1))
read operstate < /sys/class/net/$dev/operstate 2> /dev/null ||
operstate=
[ "$operstate" = up ] && : $((configured += 1))
done
[ $configured -eq $ifcount ] && [ $carriers -ge 1 ] && break
sleep 1
@@ -61,8 +64,12 @@ start ()
if [ $rc -eq 0 ] && yesno ${include_ping_test:-no}; then
ping_test_host="${ping_test_host:-google.com}"
if [ -n "$ping_test_host" ]; then
ping -c 1 $ping_test_host > /dev/null 2>&1
rc=$?
while $infinite || [ $timeout -gt 0 ]; do
ping -c 1 $ping_test_host > /dev/null 2>&1
rc=$?
[ $rc -eq 0 ] && break
: $((timeout -= 1))
done
fi
fi
eend $rc "The network is offline"

View File

@@ -76,7 +76,7 @@ tentative()
case "$RC_UNAME" in
Linux)
[ -x /sbin/ip ] || [ -x /bin/ip ] || return 1
[ -n "$(command -v ip)" ] || return 1
[ -n "$(ip -f inet6 addr show tentative)" ]
;;
*)
@@ -174,7 +174,7 @@ runip()
routeflush()
{
if [ "$RC_UNAME" = Linux ]; then
if [ -x /sbin/ip ] || [ -x /bin/ip ]; then
if [ -n "$(command -v ip)" ]; then
ip route flush scope global
ip route delete default 2>/dev/null
else
@@ -346,7 +346,7 @@ stop()
then
veinfo "$int"
runargs /etc/ifdown."$int" "$downcmd"
if [ -x /sbin/ip ] || [ -x /bin/ip ]; then
if [ -n "$(command -v ip)" ]; then
# We need to do this, otherwise we may
# fail to add things correctly on restart
ip address flush dev "$int" 2>/dev/null

View File

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

View File

@@ -16,7 +16,6 @@ depend()
after clock
use devfs
want modules
need localmount
keyword -docker -lxc -openvz -prefix -systemd-nspawn -vserver
}
@@ -27,8 +26,8 @@ start()
[ ! -e /proc/sys/fs/binfmt_misc/register ]; then
if ! grep -qs binfmt_misc /proc/filesystems &&
modprobe -q binfmt-misc; then
ewarn "The binfmt-misc module needs to be configured in" \
"@SYSCONFDIR@/conf.d/modules or built in."
ewarn "The binfmt-misc module needs to be loaded by" \
"the modules service or built in."
fi
if grep -qs binfmt_misc /proc/filesystems; then
ebegin "Mounting misc binary format filesystem"

View File

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

View File

@@ -1,4 +1,4 @@
S#!@BINDIR@/openrc-run
#!@SBINDIR@/openrc-run
# Copyright (c) 2009-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

View File

@@ -11,7 +11,7 @@
depend()
{
after clock
after clock root
before localmount
keyword -docker -jail -lxc -openvz -prefix -systemd-nspawn -vserver
}

View File

@@ -21,7 +21,7 @@ BSD_sysctl()
[ -e /etc/sysctl.conf ] || return 0
local retval=0 var= comments= conf=
eindent
for conf in @SYSCONFDIR@/sysctl.conf @SYSCONFDIR@/sysctl.d/*.conf; do
for conf in /etc/sysctl.conf /etc/sysctl.d/*.conf; do
if [ -r "$conf" ]; then
vebegin "applying $conf"
while read var comments; do

View File

@@ -101,128 +101,17 @@ mount_misc()
if [ -d /sys/firmware/efi/efivars ] &&
! mountinfo -q /sys/firmware/efi/efivars; then
ebegin "Mounting efivarfs filesystem"
mount -n -t efivarfs -o ro \
mount -n -t efivarfs -o ${sysfs_opts} \
efivarfs /sys/firmware/efi/efivars 2> /dev/null
eend 0
fi
}
cgroup1_base()
{
grep -qw cgroup /proc/filesystems || return 0
if ! mountinfo -q /sys/fs/cgroup; then
ebegin "Mounting cgroup filesystem"
local opts="${sysfs_opts},mode=755,size=${rc_cgroupsize:-10m}"
mount -n -t tmpfs -o "${opts}" cgroup_root /sys/fs/cgroup
eend $?
fi
if ! mountinfo -q /sys/fs/cgroup/openrc; then
local agent="@LIBEXECDIR@/sh/cgroup-release-agent.sh"
mkdir /sys/fs/cgroup/openrc
mount -n -t cgroup \
-o none,${sysfs_opts},name=openrc,release_agent="$agent" \
openrc /sys/fs/cgroup/openrc
printf 1 > /sys/fs/cgroup/openrc/notify_on_release
fi
return 0
}
cgroup1_controllers()
{
yesno "${rc_controller_cgroups:-YES}" && [ -e /proc/cgroups ] || return 0
while read -r name _ _ enabled rest; do
case "${enabled}" in
1) mountinfo -q "/sys/fs/cgroup/${name}" && continue
local x
for x in $rc_cgroup_controllers; do
[ "${name}" = "blkio" ] && [ "${x}" = "io" ] &&
continue 2
[ "${name}" = "${x}" ] &&
continue 2
done
mkdir "/sys/fs/cgroup/${name}"
mount -n -t cgroup -o "${sysfs_opts},${name}" \
"${name}" "/sys/fs/cgroup/${name}"
;;
esac
done < /proc/cgroups
return 0
}
cgroup2_base()
{
local base
base="$(cgroup2_find_path)"
mkdir -p "${base}"
mount -t cgroup2 none -o "${sysfs_opts},nsdelegate" "${base}" 2> /dev/null ||
mount -t cgroup2 none -o "${sysfs_opts}" "${base}"
return 0
}
cgroup2_controllers()
{
local active cgroup_path x y
cgroup_path="$(cgroup2_find_path)"
[ -z "${cgroup_path}" ] && return 0
[ -e "${cgroup_path}/cgroup.controllers" ] &&
read -r active < "${cgroup_path}/cgroup.controllers"
for x in ${rc_cgroup_controllers}; do
for y in ${active}; do
[ "$x" = "$y" ] &&
[ -e "${cgroup_path}/cgroup.subtree_control" ]&&
echo "+${x}" > "${cgroup_path}/cgroup.subtree_control"
done
done
return 0
}
cgroups_hybrid()
{
grep -qw cgroup /proc/filesystems || return 0
cgroup1_base
if grep -qw cgroup2 /proc/filesystems; then
cgroup2_base
cgroup2_controllers
fi
cgroup1_controllers
return 0
}
cgroups_legacy()
{
grep -qw cgroup /proc/filesystems || return 0
cgroup1_base
cgroup1_controllers
return 0
}
cgroups_unified()
{
cgroup2_base
cgroup2_controllers
return 0
}
mount_cgroups()
{
# set up kernel support for cgroups
if [ -d /sys/fs/cgroup ]; then
case "${rc_cgroup_mode:-hybrid}" in
hybrid) cgroups_hybrid ;;
legacy) cgroups_legacy ;;
unified) cgroups_unified ;;
esac
fi
return 0
}
restorecon_sys()
{
if [ -x /sbin/restorecon ]; then
ebegin "Restoring SELinux contexts in /sys"
restorecon -F /sys/devices/system/cpu/online >/dev/null 2>&1
restorecon -rF /sys/fs/cgroup >/dev/null 2>&1
eend $?
fi
}
@@ -231,7 +120,6 @@ start()
{
mount_sys
mount_misc
mount_cgroups
restorecon_sys
return 0
}

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 supervise-daemon.8
start-stop-daemon.8 supervise-daemon.8
ifeq (${OS},Linux)
MAN8 += rc-sstat.8 openrc-init.8 openrc-shutdown.8

View File

@@ -8,7 +8,7 @@
.\" This file may not be copied, modified, propagated, or distributed
.\" except according to the terms contained in the LICENSE file.
.\"
.Dd December 31, 2011
.Dd November 30, 2017
.Dt openrc-run 8 SMM
.Os OpenRC
.Sh NAME
@@ -111,11 +111,17 @@ The path to the s6 service directory if you are monitoring this service
with S6. The default is /var/svc.d/${RC_SVCNAME}.
.It Ar s6_svwait_options_start
The options to pass to s6-svwait when starting the service via s6.
.It Ar s6_force_kill
Should we force-kill this service if s6_service_timeout_stop expires
but the service doesn't go down during shutdown? The default is yes.
.It Ar s6_service_timeout_stop
The amount of time, in milliseconds, s6-svc should wait for the service
to go down when stopping the service. The default is 10000.
to go down when stopping the service. The default is 60000.
.It Ar start_stop_daemon_args
List of arguments passed to start-stop-daemon when starting the daemon.
.It Ar supervise_daemon_args
List of arguments passed to supervise-daemon when starting the daemon.
If undefined, start_stop_daemon_args is used as a fallback.
.It Ar command
Daemon to start or stop via
.Nm start-stop-daemon
@@ -139,21 +145,56 @@ 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) if you want
Set this to "true", "yes" or "1" (case-insensitive) if you want
.Xr start-stop-daemon 8
to force the daemon into the background. This forces the
"--make-pidfile" and "--pidfile" options, so the pidfile variable must be set.
.It Ar command_progress
Set this to "true", "yes" or "1" (case-insensitive) if you want
Set this to "true", "yes" or "1" (case-insensitive) if you want
.Xr start-stop-daemon 8
to display a progress meter when waiting for a daemon to stop.
.It Ar command_user
If the daemon does not support changing to a different user id, you can
use this to change the user id before
use this to change the user id, and optionally group id, before
.Xr start-stop-daemon 8
or
.Xr supervise-daemon 8
launches the daemon
launches the daemon.
.It Ar output_log
This is the path to a file or named pipe where the standard output from
the service will be redirected. If you are starting this service with
.Xr start-stop-daemon 8 ,
, you must set
.Pa command_background
to true. Keep in mind that this path will be inside the chroot if the
.Pa chroot
variable is set.
.It Ar error_log
The same thing as
.Pa output_log
but for the standard error output.
.It Ar output_logger
This is a process which will be used to log the standard output from the
service. If you are starting this service with
.Xr start-stop-daemon 8 ,
, you must set
.Pa command_background
to true. Keep in mind that this command must be executable as a shell
command inside the chroot if the
.Pa chroot
variable is set. Keep in mind also that this command works by accepting
the stdout of the service on stdin.
An example of a command that can be run this way is logger if you want
your service output to go to syslog.
.It Ar error_logger
The same thing as
.Pa output_logger
but for the standard error output.
.It Ar directory
.Xr start-stop-daemon 8
and
.Xr supervise-daemon 8
will chdir to this directory before starting the daemon.
.It Ar chroot
.Xr start-stop-daemon 8
and
@@ -198,6 +239,8 @@ used along with in_background_fake to support re-entrant services.
.It Ar in_background_fake
Space separated list of commands which should always succeed when
in_background is yes.
.It Ar umask
Set the umask of the daemon.
.Pp
Keep in mind that eval is used to process chroot, command, command_args_*,
command_user, pidfile and procname. This may affect how they are
@@ -217,8 +260,10 @@ that dependency type to the function, or prefix the names with ! to
remove them from the dependencies.
.Bl -tag -width "RC_DEFAULTLEVEL"
.It Ic need
The service will refuse to start until needed services have started and it
will refuse to stop until any services that need it have stopped.
The service will attempt to start any services it needs regardless of
whether they have been added to the runlevel. It will refuse to start
until all services it needs have started, and it will refuse to stop until all
services that need it have stopped.
.It Ic use
The service will attempt to start any services it uses that have been added
to the runlevel.
@@ -445,6 +490,7 @@ Also, the -d, -f or -p options should not be specified along with this option.
.Pp
The -q option suppresses all informational output. If it is specified
twice, all error messages are suppressed as well.
.It Xo
.Ic fstabinfo
.Op Fl M , -mount
.Op Fl R , -remount
@@ -461,6 +507,7 @@ remounted.
.Pp
The -q option suppresses all informational output. If it is specified
twice, all error messages are suppressed as well.
.It Xo
.Ic mountinfo
.Op Fl f, -fstype-regex Ar regex
.Op Fl F, -skip-fstype-regex Ar regex
@@ -475,7 +522,7 @@ twice, all error messages are suppressed as well.
.Op Fl i, -options
.Op Fl s, -fstype
.Op Fl t, -node
.Ar mount1 mount2 ...
.Ar mount1 mount2 ...
.Xc
The f, F, n, N, o, O, p, P, e and E options specify what you want to
search for or skip in the mounted file systems. The i, s and t options
@@ -567,7 +614,7 @@ rc_net_tap1_provide="!net"
# It's also possible to negate keywords. This is mainly useful for prefix
# users testing OpenRC.
rc_keyword="!-prefix"
# This can also be used to block a script from runining in all
# This can also be used to block a script from running in all
# containers except one or two
rc_keyword="!-containers !-docker"
.Ed
@@ -706,6 +753,8 @@ Users are encouraged to use the is_newer_than function which returns correctly.
.Xr rc_plugin_hook 3 ,
.Xr sh 1p ,
.Xr start-stop-daemon 8 ,
.Xr supervise-daemon 8 ,
.Xr uname 1
.Sh AUTHORS
.An Roy Marples <roy@marples.name>
.An William Hubbs <w.d.hubbs@gmail.com>

View File

@@ -16,6 +16,7 @@
.Nd bring the system down
.Sh SYNOPSIS
.Nm
.Op Fl c , -cancel
.Op Fl d , -no-write
.Op Fl D , -dry-run
.Op Fl H , -halt
@@ -32,6 +33,8 @@ is the utility that communicates with
to bring down the system or instruct openrc-init to re-execute itself.
It supports the following options:
.Bl -tag -width "poweroff"
.It Fl c , -cancel
Cancel a pending shutdown.
.It Fl d , -no-write
Do not write the wtmp boot record.
.It Fl D , -dry-run

View File

@@ -16,6 +16,18 @@
.Nd locate and run an OpenRC service with the given arguments
.Sh SYNOPSIS
.Nm
.Op Fl c , -ifcrashed
.Ar service cmd
.Op Ar ...
.Nm
.Fl d , -debug
.Ar service cmd
.Op Ar ...
.Nm
.Fl D , -nodeps
.Ar service cmd
.Op Ar ...
.Nm
.Op Fl i , -ifexists
.Ar service cmd
.Op Ar ...
@@ -28,9 +40,21 @@
.Ar service cmd
.Op Ar ...
.Nm
.Op Fl s , -ifstarted
.Ar service cmd
.Op Ar ...
.Nm
.Op Fl S , -ifstopped
.Ar service cmd
.Op Ar ...
.Nm
.Fl e , -exists
.Ar service
.Nm
.Fl Z , -dry-run
.Ar service cmd
.Op Ar ...
.Nm
.Fl l , -list
.Nm
.Fl r , -resolve
@@ -64,6 +88,15 @@ return 0 if it can find
otherwise -1.
.Fl r , -resolve
does the same and also prints the full path of the service to stdout.
.Pp
.Fl d , -debug
sets -x when running the service script(s).
.Pp
.Fl D , -nodeps
ignores dependencies when running the service.
.Pp
.Fl Z , -dry-run
displays commands rather than executing them.
.Sh SEE ALSO
.Xr openrc 8 ,
.Xr stdout 3

View File

@@ -1 +0,0 @@
.so rc-service.8

View File

@@ -131,9 +131,34 @@ Modifies the scheduling priority of the daemon.
.It Fl 1 , -stdout Ar logfile
Redirect the standard output of the process to logfile when started with
.Fl background .
Must be an absolute pathname, but relative to the path optionally given with
The 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
Redirect the standard error of the process to logfile when started with
.Fl background .
The 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 3 , -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 4 , -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 w , -wait Ar milliseconds
Wait
.Ar milliseconds
@@ -151,6 +176,7 @@ These options are only used for stopping daemons:
.It Fl R , -retry Ar timeout | Ar signal Ns / Ns Ar timeout
The retry specification can be either a timeout in seconds or multiple
signal/timeout pairs (like SIGTERM/5).
If this option is not given, the default is SIGTERM/5.
.El
.Sh ENVIRONMENT
.Va SSD_IONICELEVEL

View File

@@ -16,6 +16,10 @@
.Nd starts a daemon and restarts it if it crashes
.Sh SYNOPSIS
.Nm
.Fl a , -healthcheck-timer
.Ar seconds
.Fl A , -healthcheck-delay
.Ar seconds
.Fl D , -respawn-delay
.Ar seconds
.Fl d , -chdir
@@ -90,6 +94,11 @@ Print the action(s) that are taken just before doing them.
.Pp
The options are as follows:
.Bl -tag -width indent
.Fl a , -healthcheck-timer Ar seconds
Run the healthcheck() command, possibly followed by the unhealthy()
command every time this number of seconds passes.
.Fl A , -healthcheck-delay Ar seconds
Wait this long before the first health check.
.It Fl D , -respawn-delay Ar seconds
wait this number of seconds before restarting a daemon after it crashes.
The default is 0.
@@ -120,6 +129,7 @@ description of --respawn-max for more information.
.It Fl R , -retry Ar timeout | Ar signal Ns / Ns Ar timeout
The retry specification can be either a timeout in seconds or multiple
signal/timeout pairs (like SIGTERM/5).
If this option is not given, the default is SIGTERM/5.
.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.

View File

@@ -11,3 +11,5 @@
# Generic definitions
include ${MK}/os-BSD.mk
CPPFLAGS+= -D_BSD_SOURCE

View File

@@ -13,6 +13,6 @@
SFX= .GNU-kFreeBSD.in
PKG_PREFIX?= /usr
CPPFLAGS+= -D_BSD_SOURCE -D_XOPEN_SOURCE=700
CPPFLAGS+= -D_BSD_SOURCE
LIBDL= -Wl,-Bdynamic -ldl
LIBKVM?=

View File

@@ -11,5 +11,5 @@
SFX= .GNU.in
PKG_PREFIX?= /usr
CPPFLAGS+= -D_DEFAULT_SOURCE -D_XOPEN_SOURCE=700 -DMAXPATHLEN=4096 -DPATH_MAX=4096
CPPFLAGS+= -D_DEFAULT_SOURCE -DMAXPATHLEN=4096 -DPATH_MAX=4096
LIBDL= -Wl,-Bdynamic -ldl

View File

@@ -11,7 +11,7 @@
SFX= .Linux.in
PKG_PREFIX?= /usr
CPPFLAGS+= -D_DEFAULT_SOURCE -D_XOPEN_SOURCE=700
CPPFLAGS+= -D_DEFAULT_SOURCE -D_POSIX_C_SOURCE=200809L
LIBDL= -Wl,-Bdynamic -ldl
ifeq (${MKSELINUX},yes)

View File

@@ -34,6 +34,7 @@ PICFLAG?= -fPIC
SYSCONFDIR?= ${PREFIX}/etc
INITDIR?= ${SYSCONFDIR}/init.d
CONFDIR?= ${SYSCONFDIR}/conf.d
CONFMODE?= 0644
LOCALDIR?= ${SYSCONFDIR}/local.d
SYSCTLDIR?= ${SYSCONFDIR}/sysctl.d
@@ -44,20 +45,22 @@ SBINDIR?= ${PREFIX}/sbin
SBINMODE?= 0755
INCDIR?= ${UPREFIX}/include
INCMODE?= 0444
INCMODE?= 0644
_LIBNAME_SH= case `readlink /lib` in /lib64|lib64) echo "lib64";; *) echo "lib";; esac
_LIBNAME:= $(shell ${_LIBNAME_SH})
LIBNAME?= ${_LIBNAME}
LIBDIR?= ${UPREFIX}/${LIBNAME}
LIBMODE?= 0444
LIBMODE?= 0644
SHLIBDIR?= ${PREFIX}/${LIBNAME}
LIBEXECDIR?= ${PREFIX}/libexec/rc
MANPREFIX?= ${UPREFIX}/share
MANDIR?= ${MANPREFIX}/man
MANMODE?= 0444
MANMODE?= 0644
BASHCOMPDIR?= ${UPREFIX}/share/bash-completion/completions
DATADIR?= ${UPREFIX}/share/openrc
DATAMODE?= 0644
@@ -65,4 +68,4 @@ DATAMODE?= 0644
DOCDIR?= ${UPREFIX}/share/doc
DOCMODE?= 0644
CONFMODE?= 0644
ZSHCOMPDIR?= ${UPREFIX}/share/zsh/site-functions

View File

@@ -1,4 +1,5 @@
# Using runit with OpenRC
Using runit with OpenRC
=======================
Beginning with OpenRC-0.21, we support using runit [1] in place of
start-stop-daemon for monitoring and restarting daemons.

View File

@@ -38,7 +38,7 @@ BOOT-FreeBSD+= adjkerntz dumpon syscons
BOOT-Linux+= binfmt hwclock keymaps modules mtab procfs termencoding
SHUTDOWN-Linux= killprocs mount-ro
SYSINIT-Linux= devfs dmesg sysfs
SYSINIT-Linux= devfs cgroups dmesg sysfs
# Generic BSD stuff
BOOT-NetBSD+= hostid newsyslog savecore syslogd

View File

@@ -1,4 +1,5 @@
# Using S6 with OpenRC
Using S6 with OpenRC
====================
Beginning with OpenRC-0.16, we support using the s6 supervision suite
from Skarnet Software in place of start-stop-daemon for monitoring
@@ -39,6 +40,10 @@ s6_service_path - the path to the s6 service directory. The default is
s6_svwait_options_start - the options to pass to s6-svwait when starting
the service. If this is not set, s6-svwait will not be called.
s6_force_kill - Should we try to force kill this service if the
s6_service_timeout_stop timeout expires when shutting down this service?
The default is yes.
s6_service_timeout_stop - the amount of time, in milliseconds, s6-svc
should wait for a service to go down when stopping.

495
service-script-guide.md Normal file
View File

@@ -0,0 +1,495 @@
OpenRC Service Script Writing Guide
===================================
This document is aimed at developers or packagers who
write OpenRC service scripts, either for their own projects, or for
the packages they maintain. It contains advice, suggestions, tips,
tricks, hints, and counsel; cautions, warnings, heads-ups,
admonitions, proscriptions, enjoinders, and reprimands.
It is intended to prevent common mistakes that are found "in the wild"
by pointing out those mistakes and suggesting alternatives. Each
good/bad thing that you should/not do has a section devoted to it. We
don't consider anything exotic, and assume that you will use
start-stop-daemon to manage a fairly typical long-running UNIX
process.
# 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 service scripts 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 and should be used unless you have a very strong reason not to
use them.
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 `lib/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
## Don't write your own start/stop functions
OpenRC is capable of stopping and starting most daemons based on the
information that you give it. For a well-behaved daemon that
backgrounds itself and writes its own PID file by default, the
following OpenRC variables are likely all that you'll need:
* command
* command_args
* pidfile
Given those three pieces of information, OpenRC will be able to start
and stop the daemon on its own. The following is taken from an
[OpenNTPD](http://www.openntpd.org/) service script:
```sh
command="/usr/sbin/ntpd"
# The special RC_SVCNAME variable contains the name of this service.
pidfile="/run/${RC_SVCNAME}.pid"
command_args="-p ${pidfile}"
```
If the daemon runs in the foreground by default but has options to
background itself and to create a pidfile, then you'll also need
* command_args_background
That variable should contain the flags needed to background your
daemon, and to make it write a PID file. Take for example the
following snippet of an
[NRPE](https://github.com/NagiosEnterprises/nrpe) service script:
```sh
command="/usr/bin/nrpe"
command_args="--config=/etc/nagios/nrpe.cfg"
command_args_background="--daemon"
pidfile="/run/${RC_SVCNAME}.pid"
```
Since NRPE runs as *root* by default, it needs no special permissions
to write to `/run/nrpe.pid`. OpenRC takes care of starting and
stopping the daemon with the appropriate arguments, even passing the
`--daemon` flag during startup to force NRPE into the background (NRPE
knows how to write its own PID file).
But what if the daemon isn't so well behaved? What if it doesn't know
how to background itself or create a pidfile? If it can do neither,
then use,
* command_background=true
which will additionally pass `--make-pidfile` to start-stop-daemon,
causing it to create the `$pidfile` for you (rather than the daemon
itself being responsible for creating the PID file).
If your daemon doesn't know how to change its own user or group, then
you can tell start-stop-daemon to launch it as an unprivileged user
with
* command_user="user:group"
Finally, if your daemon always forks into the background but fails to
create a PID file, then your only option is to use
* procname
With `procname`, OpenRC will try to find the running daemon by
matching the name of its process. That's not so reliable, but daemons
shouldn't background themselves without creating a PID file in the
first place. The next example is part of the [CA NetConsole
Daemon](https://oss.oracle.com/projects/cancd/) service script:
```sh
command="/usr/sbin/cancd"
command_args="-p ${CANCD_PORT}
-l ${CANCD_LOG_DIR}
-o ${CANCD_LOG_FORMAT}"
command_user="cancd"
# cancd daemonizes itself, but doesn't write a PID file and doesn't
# have an option to run in the foreground. So, the best we can do
# is try to match the process name when stopping it.
procname="cancd"
```
To recap, in order of preference:
1. If the daemon backgrounds itself and creates its own PID file, use
`pidfile`.
2. If the daemon does not background itself (or has an option to run
in the foreground) and does not create a PID file, then use
`command_background=true` and `pidfile`.
3. If the daemon backgrounds itself and does not create a PID file,
use `procname` instead of `pidfile`. But, if your daemon has the
option to run in the foreground, then you should do that instead
(that would be the case in the previous item).
4. The last case, where the daemon does not background itself but
does create a PID file, doesn't make much sense. If there's a way
to disable the daemon's PID file (or, to write it straight into the
garbage), then do that, and use `command_background=true`.
## Reloading your daemon's configuration
Many daemons will reload their configuration files in response to a
signal. Suppose your daemon will reload its configuration in response
to a `SIGHUP`. It's possible to add a new "reload" command to your
service script that performs this action. First, tell the service
script about the new command.
```sh
extra_started_commands="reload"
```
We use `extra_started_commands` as opposed to `extra_commands` because
the "reload" action is only valid while the daemon is running (that
is, started). Now, start-stop-daemon can be used to send the signal to
the appropriate process (assuming you've defined the `pidfile`
variable elsewhere):
```sh
reload() {
ebegin "Reloading ${RC_SVCNAME}"
start-stop-daemon --signal HUP --pidfile "${pidfile}"
eend $?
}
```
## Don't restart/reload with a broken config
Often, users will start a daemon, make some configuration change, and
then attempt to restart the daemon. If the recent configuration change
contains a mistake, the result will be that the daemon is stopped but
then cannot be started again (due to the configuration error). It's
possible to prevent that situation with a function that checks for
configuration errors, and a combination of the `start_pre` and
`stop_pre` hooks.
```sh
checkconfig() {
# However you want to check this...
}
start_pre() {
# If this isn't a restart, make sure that the user's config isn't
# busted before we try to start the daemon (this will produce
# better error messages than if we just try to start it blindly).
#
# If, on the other hand, this *is* a restart, then the stop_pre
# action will have ensured that the config is usable and we don't
# need to do that again.
if [ "${RC_CMD}" != "restart" ] ; then
checkconfig || return $?
fi
}
stop_pre() {
# If this is a restart, check to make sure the user's config
# isn't busted before we stop the running daemon.
if [ "${RC_CMD}" = "restart" ] ; then
checkconfig || return $?
fi
}
```
To prevent a *reload* with a broken config, keep it simple:
```sh
reload() {
checkconfig || return $?
ebegin "Reloading ${RC_SVCNAME}"
start-stop-daemon --signal HUP --pidfile "${pidfile}"
eend $?
}
```
## PID files should be writable only by root
PID files must be writable only by *root*, which means additionally
that they must live in a *root*-owned directory. This directory is
normally /run under Linux and /var/run under other operating systems.
Some daemons run as an unprivileged user account, and create their PID
files (as the unprivileged user) in a path like
`/var/run/foo/foo.pid`. That can usually be exploited by the unprivileged
user to kill *root* processes, since when a service is stopped, *root*
usually sends a SIGTERM to the contents of the PID file (which are
controlled by the unprivileged user). The main warning sign for that
problem is using `checkpath` to set ownership on the directory
containing the PID file. For example,
```sh
# BAD BAD BAD BAD BAD BAD BAD BAD
start_pre() {
# Ensure that the pidfile directory is writable by the foo user/group.
checkpath --directory --mode 0700 --owner foo:foo "/var/run/foo"
}
# BAD BAD BAD BAD BAD BAD BAD BAD
```
If the *foo* user owns `/var/run/foo`, then he can put whatever he wants
in the `/var/run/foo/foo.pid` file. Even if *root* owns the PID file, the
*foo* user can delete it and replace it with his own. To avoid
security concerns, the PID file must be created as *root* and live in
a *root*-owned directory. If your daemon is responsible for forking
and writing its own PID file but the PID file is still owned by the
unprivileged runtime user, then you may have an upstream issue.
Once the PID file is being created as *root* (before dropping
privileges), it can be written directly to a *root*-owned
directory. For example, the *foo* daemon might write
`/var/run/foo.pid`. No calls to checkpath are needed. Note: there is
nothing technically wrong with using a directory structure like
`/var/run/foo/foo.pid`, so long as *root* owns the PID file and the
directory containing it.
Ideally (see "Upstream your service scripts"), your service script
will be integrated upstream and the build system will determine the
appropriate directory for the pid file. For example,
```sh
pidfile="@piddir@/${RC_SVCNAME}.pid"
```
A decent example of this is the [Nagios core service
script](https://github.com/NagiosEnterprises/nagioscore/blob/master/openrc-init.in),
where the full path to the PID file is specified at build-time.
## Don't let the user control the PID file location
It's usually a mistake to let the end user control the PID file
location through a conf.d variable, for a few reasons:
1. When the PID file path is controlled by the user, you need to
ensure that its parent directory exists and is writable. This
adds unnecessary code to the service script.
2. If the PID file path changes while the service is running, then
you'll find yourself unable to stop the service.
3. The directory that should contain the PID file is best determined
by the upstream build system (see "Upstream your service scripts").
On Linux, the preferred location these days is `/run`. Other systems
still use `/var/run`, though, and a `./configure` script is the
best place to decide which one you want.
4. Nobody cares where the PID file is located, anyway.
Since OpenRC service names must be unique, a value of
```sh
pidfile="/var/run/${RC_SVCNAME}.pid"
```
guarantees that your PID file has a unique name.
## Upstream your service scripts (for packagers)
The ideal place for an OpenRC service script is **upstream**. Much like
systemd services, a well-crafted OpenRC service script should be
distribution-agnostic, and the best place for it is upstream. Why? For
two reasons. First, having it upstream means that there's a single
authoritative source for improvements. Second, a few paths in every
service script are dependent upon flags passed to the build system. For
example,
```sh
command=/usr/bin/foo
```
in an autotools-based build system should really be
```sh
command=@bindir@/foo
```
so that the user's value of `--bindir` is respected. If you keep the
service script in your own distribution's repository, then you have to
keep the command path and package synchronized yourself, and that's no
fun.
## Be wary of "need net" dependencies
There are two things you need to know about "need net" dependencies:
1. They are not satisfied by the loopback interface, so "need net"
requires some *other* interface to be up.
2. Depending on the value of `rc_depend_strict` in `rc.conf`, the
"need net" will be satisfied when either *any* non-loopback
interface is up, or when *all* non-loopback interfaces are up.
The first item means that "need net" is wrong for daemons that are
happy with `0.0.0.0`, and the second point means that "need net" is
wrong for daemons that need a particular (for example, the WAN)
interface. We'll consider the two most common users of "need net";
network clients who access some network resource, and network servers
who provide them.
### Network clients
Network clients typically want the WAN interface to be up. That may
tempt you to depend on the WAN interface; but first, you should ask
yourself a question: does anything bad happen if the WAN interface is
not available? In other words, if the administrator wants to disable
the WAN, should the service be stopped? Usually the answer to that
question is "no," and in that case, you should forego the "net"
dependency entirely.
Suppose, for example, that your service retrieves virus signature
updates from the internet. In order to do its job correctly, it needs
a (working) internet connection. However, the service itself does not
require the WAN interface to be up: if it is, great; otherwise, the
worst that will happen is that a "server unavailable" warning will be
logged. The signature update service will not crash, and—perhaps more
importantly—you don't want it to terminate if the administrator turns
off the WAN interface for a second.
### Network servers
Network servers are generally easier to handle than their client
counterparts. Most server daemons listen on `0.0.0.0` (all addresses)
by default, and are therefore satisfied to have the loopback interface
present and operational. OpenRC ships with the loopback service in the
*boot* runlevel, and therefore most server daemons require no further
network dependencies.
The exceptions to this rule are those daemons who produce negative
side-effects when the WAN is unavailable. For example, the Nagios
server daemon will generate "the sky is falling" alerts for as long as
your monitored hosts are unreachable. So in that case, you should
require some other interface (often the WAN) to be up. A "need"
dependency would be appropriate, because you want Nagios to be
stopped before the network is taken down.
If your daemon can optionally be configured to listen on a particular
interface, then please see the "Depending on a particular interface"
section.
### Depending on a particular interface
If you need to depend on one particular interface, usually it's not
easy to determine programmatically what that interface is. For
example, if your *sshd* daemon listens on `192.168.1.100` (rather than
`0.0.0.0`), then you have two problems:
1. Parsing `sshd_config` to figure that out; and
2. Determining which network service name corresponds to the
interface for `192.168.1.100`.
It's generally a bad idea to parse config files in your service
scripts, but the second problem is the harder one. Instead, the most
robust (i.e. the laziest) approach is to make the user specify the
dependency when he makes a change to sshd_config. Include something
like the following in the service configuration file,
```sh
# Specify the network service that corresponds to the "bind" setting
# in your configuration file. For example, if you bind to 127.0.0.1,
# this should be set to "loopback" which provides the loopback interface.
rc_need="loopback"
```
This is a sensible default for daemons that are happy with `0.0.0.0`,
but lets the user specify something else, like `rc_need="net.wan"` if
he needs it. The burden is on the user to determine the appropriate
service whenever he changes the daemon's configuration file.

1
sh/.gitignore vendored
View File

@@ -1,6 +1,5 @@
functions.sh
gendepends.sh
rc-functions.sh
openrc-run.sh
cgroup-release-agent.sh
init.sh

View File

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

View File

@@ -33,6 +33,9 @@ else
kmode="-a"
fi
# Set the SELinux label on console before everything so we dont lose output
[ -x /sbin/restorecon ] && /sbin/restorecon -F /dev/console
# Try and set a font and as early as we can
if service_present "$RC_DEFAULTLEVEL" consolefont ||
service_present "$RC_BOOTLEVEL" consolefont; then

View File

@@ -83,6 +83,7 @@ elif ! mountinfo -q /run; then
fi
fi
[ -x /sbin/restorecon ] && /sbin/restorecon -rF /run
checkpath -d $RC_SVCDIR
checkpath -d -m 0775 -o root:uucp /run/lock

View File

@@ -133,11 +133,10 @@ _status()
elif service_inactive; then
ewarn "status: inactive"
return 16
elif service_crashed; then
eerror "status: crashed"
return 32
elif service_started; then
if service_crashed; then
eerror "status: crashed"
return 32
fi
einfo "status: started"
return 0
else
@@ -260,12 +259,14 @@ for _cmd; do
# Apply cgroups settings if defined
if [ "$(command -v cgroup_add_service)" = "cgroup_add_service" ]
then
if [ -d /sys/fs/cgroup -a ! -w /sys/fs/cgroup ]; then
eerror "No permission to apply cgroup settings"
break
if grep -qs /sys/fs/cgroup /proc/1/mountinfo
then
if [ -d /sys/fs/cgroup -a ! -w /sys/fs/cgroup ]; then
eerror "No permission to apply cgroup settings"
break
fi
fi
cgroup_add_service /sys/fs/cgroup/openrc
cgroup_add_service /sys/fs/cgroup/systemd/system
cgroup_add_service
fi
[ "$(command -v cgroup_set_limits)" = "cgroup_set_limits" ] &&
cgroup_set_limits

View File

@@ -62,7 +62,7 @@ cgroup_set_values()
while [ -n "$1" ] && [ "$controller" != "cpuacct" ]; do
case "$1" in
$controller.*)
if [ -n "${name}" ] && [ -w "${cgroup}/${name}" ] &&
if [ -n "${name}" ] && [ -w "${cgroup}/${name}" ] &&
[ -n "${val}" ]; then
veinfo "$RC_SVCNAME: Setting $cgroup/$name to $val"
printf "%s" "$val" > "$cgroup/$name"
@@ -165,7 +165,7 @@ cgroup2_remove()
[ ! -e "${rc_cgroup_path}"/cgroup.events ] &&
return 0
grep -qx "$$" "${rc_cgroup_path}/cgroup.procs" &&
echo 0 > "${cgroup_path}/cgroup.procs"
printf "%d" 0 > "${cgroup_path}/cgroup.procs"
local key populated vvalue
while read -r key value; do
case "${key}" in
@@ -184,18 +184,17 @@ cgroup2_set_limits()
cgroup_path="$(cgroup2_find_path)"
[ -d "${cgroup_path}" ] || return 0
rc_cgroup_path="${cgroup_path}/${RC_SVCNAME}"
local OIFS="$IFS"
IFS="
"
[ ! -d "${rc_cgroup_path}" ] && mkdir "${rc_cgroup_path}"
echo 0 > "${rc_cgroup_path}/cgroup.procs"
echo "${rc_cgroup_settings}" | while IFS="$OIFS" read -r key value; do
[ -z "${key}" ] || [ -z "${value}" ] && continue
[ ! -e "${rc_cgroup_path}/${key}" ] && continue
veinfo "${RC_SVCNAME}: cgroups: ${key} ${value}"
echo "${value}" > "${rc_cgroup_path}/${key}"
[ -f "${rc_cgroup_path}"/cgroup.procs ] &&
printf 0 > "${rc_cgroup_path}"/cgroup.procs
[ -z "${rc_cgroup_settings}" ] && return 0
echo "${rc_cgroup_settings}" | while read -r key value; do
[ -z "${key}" ] && continue
[ -z "${value}" ] && continue
[ ! -f "${rc_cgroup_path}/${key}" ] && continue
veinfo "${RC_SVCNAME}: cgroups: setting ${key} to ${value}"
printf "%s\n" "${value}" > "${rc_cgroup_path}/${key}"
done
IFS="$OIFS"
return 0
}
@@ -203,15 +202,21 @@ cgroup_cleanup()
{
cgroup_running || return 0
ebegin "starting cgroups cleanup"
local pids
local pids loops=0
pids="$(cgroup_get_pids)"
if [ -n "${pids}" ]; then
kill -s "${stopsig:-TERM}" ${pids} 2> /dev/null
kill -s CONT ${pids} 2> /dev/null
kill -s "${stopsig:-TERM}" ${pids} 2> /dev/null
yesno "${rc_send_sighup:-no}" &&
kill -s HUP ${pids} 2> /dev/null
sleep "${rc_timeout_stopsec:-90}"
yesno "${rc_send_sigkill:-yes}" &&
kill -s "${stopsig:-TERM}" ${pids} 2> /dev/null
while [ -n "$(cgroup_get_pids)" ] &&
[ "${loops}" -lt "${rc_timeout_stopsec:-90}" ]; do
loops=$((loops+1))
sleep 1
done
pids="$(cgroup_get_pids)"
[ -n "${pids}" ] && yesno "${rc_send_sigkill:-yes}" &&
kill -s KILL ${pids} 2> /dev/null
fi
cgroup2_remove

View File

@@ -2,42 +2,6 @@
# Copyright (c) 2007-2009 Roy Marples <roy@marples.name>
# Released under the 2-clause BSD license.
has_addon()
{
[ -e /@LIB@/rc/addons/"$1".sh -o -e /@LIB@/rcscripts/addons/"$1".sh ]
}
_addon_warn()
{
eindent
ewarn "$RC_SVCNAME uses addon code which is deprecated"
ewarn "and may not be available in the future."
eoutdent
}
import_addon()
{
if [ -e /@LIB@/rc/addons/"$1".sh ]; then
_addon_warn
. /@LIB@/rc/addons/"$1".sh
elif [ -e /@LIB@/rcscripts/addons/"$1".sh ]; then
_addon_warn
. /@LIB@/rcscripts/addons/"$1".sh
else
return 1
fi
}
start_addon()
{
( import_addon "$1-start" )
}
stop_addon()
{
( import_addon "$1-stop" )
}
net_fs_list="afs ceph cifs coda davfs fuse fuse.sshfs gfs glusterfs lustre
ncpfs nfs nfs4 ocfs2 shfs smbfs"
is_net_fs()
@@ -119,6 +83,13 @@ get_bootparam_value()
echo $result
}
need_if_exists()
{
for x; do
rc-service --exists "${x}" && need "${x}"
done
}
# Called from openrc-run.sh or gendepends.sh
_get_containers() {
local c

View File

@@ -12,6 +12,20 @@
[ -z "${s6_service_path}" ] && s6_service_path="/var/svc.d/${RC_SVCNAME}"
_s6_force_kill() {
local pid
s6_service_link="${RC_SVCDIR}/s6-scan/${s6_service_path##*/}"
pid="${3%)}"
[ -z "${pid}" ] && return 0
if kill -0 "${pid}" 2> /dev/null; then
ewarn "Sending DOWN & KILL for ${RC_SVCNAME}"
s6-svc -dk "${s6_service_link}"
sleep 1
kill -0 "${pid}" 2>/dev/null && return 1
fi
return 0
}
s6_start()
{
if [ ! -d "${s6_service_path}" ]; then
@@ -41,7 +55,11 @@ s6_stop()
fi
s6_service_link="${RC_SVCDIR}/s6-scan/${s6_service_path##*/}"
ebegin "Stopping ${name:-$RC_SVCNAME}"
s6-svc -wD -d -T ${s6_service_timeout_stop:-10000} "${s6_service_link}"
s6-svc -d -wD -T ${s6_service_timeout_stop:-60000} "${s6_service_link}"
set -- $(s6-svstat "${s6_service_link}")
[ "$1" = "up" ] &&
yesno "${s6_force_kill:-yes}" &&
_s6_force_kill "$@"
set -- $(s6-svstat "${s6_service_link}")
[ "$1" = "down" ]
eend $? "Failed to stop ${name:-$RC_SVCNAME}"

View File

@@ -38,15 +38,25 @@ ssd_start()
service_inactive && _inactive=true
mark_service_inactive
fi
[ -n "$output_logger" ] &&
output_logger_arg="--stdout-logger \"$output_logger\""
[ -n "$error_logger" ] &&
error_logger_arg="--stderr-logger \"$error_logger\""
#the eval call is necessary for cases like:
# command_args="this \"is a\" test"
# to work properly.
eval start-stop-daemon --start \
--exec $command \
${chroot:+--chroot} $chroot \
${directory:+--chdir} $directory \
${output_log+--stdout} $output_log \
${error_log+--stderr} $error_log \
${output_logger_arg} \
${error_logger_arg} \
${procname:+--name} $procname \
${pidfile:+--pidfile} $pidfile \
${command_user+--user} $command_user \
${umask+--umask} $umask \
$_background $start_stop_daemon_args \
-- $command_args $command_args_background
if eend $? "Failed to start ${name:-$RC_SVCNAME}"; then

View File

@@ -10,6 +10,8 @@
# This file may not be copied, modified, propagated, or distributed
# except according to the terms contained in the LICENSE file.
extra_commands="healthcheck unhealthy ${extra_commands}"
supervise_start()
{
if [ -z "$command" ]; then
@@ -22,15 +24,21 @@ supervise_start()
# The eval call is necessary for cases like:
# command_args="this \"is a\" test"
# to work properly.
eval supervise-daemon --start \
eval supervise-daemon "${RC_SVCNAME}" --start \
${retry:+--retry} $retry \
${directory:+--chdir} $directory \
${chroot:+--chroot} $chroot \
${output_log+--stdout} ${output_log} \
${error_log+--stderr} $error_log \
${pidfile:+--pidfile} $pidfile \
${respawn_delay:+--respawn-delay} $respawn_delay \
${respawn_max:+--respawn-max} $respawn_max \
${respawn_period:+--respawn-period} $respawn_period \
${healthcheck_delay:+--healthcheck-delay} $healthcheck_delay \
${healthcheck_timer:+--healthcheck-timer} $healthcheck_timer \
${command_user+--user} $command_user \
$supervise_daemon_args \
${umask+--umask} $umask \
${supervise_daemon_args:-${start_stop_daemon_args}} \
$command \
-- $command_args $command_args_foreground
rc=$?
@@ -49,14 +57,58 @@ supervise_stop()
pidfile="${startpidfile:-$pidfile}"
[ -n "$pidfile" ] || return 0
ebegin "Stopping ${name:-$RC_SVCNAME}"
supervise-daemon --stop \
supervise-daemon "${RC_SVCNAME}" --stop \
${pidfile:+--pidfile} $chroot$pidfile \
${stopsig:+--signal} $stopsig
eend $? "Failed to stop ${name:-$RC_SVCNAME}"
}
_check_supervised()
{
local child_pid start_time
child_pid="$(service_get_value "child_pid")"
start_time="$(service_get_value "start_time")"
if [ -n "${child_pid}" ] && [ -n "${start_time}" ]; then
return 1
fi
return 0
}
supervise_status()
{
_status
if service_stopping; then
ewarn "status: stopping"
return 4
elif service_starting; then
ewarn "status: starting"
return 8
elif service_inactive; then
ewarn "status: inactive"
return 16
elif service_started; then
if service_crashed; then
if ! _check_supervised; then
eerror "status: unsupervised"
return 64
fi
eerror "status: crashed"
return 32
fi
einfo "status: started"
return 0
else
einfo "status: stopped"
return 3
fi
}
healthcheck()
{
return 0
}
unhealthy()
{
return 0
}

View File

@@ -28,9 +28,11 @@
#if __GNUC__ > 2 || defined(__INTEL_COMPILER)
# define _dead __attribute__((__noreturn__))
# define _unused __attribute__((__unused__))
# define _xasprintf(a, b) __attribute__((__format__(__printf__, a, b)))
#else
# define _dead
# define _unused
# define _xasprintf(a, b)
#endif
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
@@ -53,6 +55,7 @@
} while (/* CONSTCOND */ 0)
#endif
#include <stdarg.h>
#include <stdbool.h>
#include <sys/stat.h>
@@ -96,8 +99,10 @@ _unused static char *xstrdup(const char *str)
#undef ERRX
/* basename_c never modifies the argument. As such, if there is a trailing
* slash then an empty string is returned. */
/*
* basename_c never modifies the argument. As such, if there is a trailing
* slash then an empty string is returned.
*/
_unused static const char *basename_c(const char *path)
{
const char *slash = strrchr(path, '/');
@@ -121,4 +126,49 @@ _unused static bool existss(const char *pathname)
return (stat(pathname, &buf) == 0 && buf.st_size != 0);
}
/*
* This is an OpenRC specific version of the asprintf() function.
* We do this to avoid defining the _GNU_SOURCE feature test macro on
* glibc systems and to insure that we have a consistent function across
* platforms. This also allows us to call our xmalloc and xrealloc
* functions to handle memory allocation.
* this function was originally written by Mike Frysinger.
*/
_unused _xasprintf(2,3) static int xasprintf(char **strp, const char *fmt, ...)
{
va_list ap;
int len;
int memlen;
char *ret;
/*
* Start with a buffer size that should cover the vast majority of uses
* (path construction).
*/
memlen = 4096;
ret = xmalloc(memlen);
va_start(ap, fmt);
len = vsnprintf(ret, memlen, fmt, ap);
va_end(ap);
if (len >= memlen) {
/*
* Output was truncated, so increase buffer to exactly what we need.
*/
memlen = len + 1;
ret = xrealloc(ret, memlen);
va_start(ap, fmt);
len = vsnprintf(ret, len + 1, fmt, ap);
va_end(ap);
}
if (len < 0 || len >= memlen) {
/* Give up! */
fprintf(stderr, "xasprintf: unable to format a buffer\n");
free(ret);
exit(1);
}
*strp = ret;
return len;
}
#endif

View File

@@ -47,6 +47,7 @@ bool rc_conf_yesno(const char *var);
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_unlock(const char *, int);
pid_t exec_service(const char *, const char *);
@@ -65,9 +66,6 @@ int parse_mode(mode_t *, char *);
/* Handy function so we can wrap einfo around our deptree */
RC_DEPTREE *_rc_deptree_load (int, int *);
/* Test to see if we can see pid 1 or not */
bool _rc_can_find_pids(void);
RC_SERVICE lookup_service_state(const char *service);
void from_time_t(char *time_string, time_t tv);
time_t to_time_t(char *timestring);

View File

@@ -883,7 +883,7 @@ eindent(void)
{
char *env = getenv("EINFO_INDENT");
int amount = 0;
char num[10];
char *num;
if (env) {
errno = 0;
@@ -894,8 +894,9 @@ eindent(void)
amount += INDENT_WIDTH;
if (amount > INDENT_MAX)
amount = INDENT_MAX;
snprintf(num, 10, "%08d", amount);
xasprintf(&num, "%08d", amount);
setenv("EINFO_INDENT", num, 1);
free(num);
}
hidden_def(eindent)
@@ -903,7 +904,7 @@ void eoutdent(void)
{
char *env = getenv("EINFO_INDENT");
int amount = 0;
char num[10];
char *num = NULL;
int serrno = errno;
if (!env)
@@ -917,8 +918,9 @@ void eoutdent(void)
if (amount <= 0)
unsetenv("EINFO_INDENT");
else {
snprintf(num, 10, "%08d", amount);
xasprintf(&num, "%08d", amount);
setenv("EINFO_INDENT", num, 1);
free(num);
}
errno = serrno;
}

View File

@@ -23,13 +23,13 @@
static bool
pid_is_exec(pid_t pid, const char *exec)
{
char buffer[32];
char *buffer = NULL;
FILE *fp;
int c;
bool retval = false;
exec = basename_c(exec);
snprintf(buffer, sizeof(buffer), "/proc/%d/stat", pid);
xasprintf(&buffer, "/proc/%d/stat", pid);
if ((fp = fopen(buffer, "r"))) {
while ((c = getc(fp)) != EOF && c != '(')
;
@@ -41,23 +41,27 @@ pid_is_exec(pid_t pid, const char *exec)
}
fclose(fp);
}
free(buffer);
return retval;
}
static bool
pid_is_argv(pid_t pid, const char *const *argv)
{
char cmdline[32];
char *cmdline = NULL;
int fd;
char buffer[PATH_MAX];
char *p;
ssize_t bytes;
snprintf(cmdline, sizeof(cmdline), "/proc/%u/cmdline", pid);
if ((fd = open(cmdline, O_RDONLY)) < 0)
xasprintf(&cmdline, "/proc/%u/cmdline", pid);
if ((fd = open(cmdline, O_RDONLY)) < 0) {
free(cmdline);
return false;
}
bytes = read(fd, buffer, sizeof(buffer));
close(fd);
free(cmdline);
if (bytes == -1)
return false;
@@ -80,12 +84,15 @@ rc_find_pids(const char *exec, const char *const *argv, uid_t uid, pid_t pid)
DIR *procdir;
struct dirent *entry;
FILE *fp;
int rc;
bool container_pid = false;
bool openvz_host = false;
char *line = NULL;
char my_ns[30];
char proc_ns[30];
size_t len = 0;
pid_t p;
char buffer[PATH_MAX];
char *buffer = NULL;
struct stat sb;
pid_t openrc_pid = 0;
char *pp;
@@ -131,6 +138,14 @@ rc_find_pids(const char *exec, const char *const *argv, uid_t uid, pid_t pid)
}
}
memset(my_ns, 0, sizeof(my_ns));
memset(proc_ns, 0, sizeof(proc_ns));
if (exists("/proc/self/ns/pid")) {
rc = readlink("/proc/self/ns/pid", my_ns, sizeof(my_ns));
if (rc <= 0)
my_ns[0] = '\0';
}
while ((entry = readdir(procdir)) != NULL) {
if (sscanf(entry->d_name, "%d", &p) != 1)
continue;
@@ -138,10 +153,22 @@ rc_find_pids(const char *exec, const char *const *argv, uid_t uid, pid_t pid)
continue;
if (pid != 0 && pid != p)
continue;
xasprintf(&buffer, "/proc/%d/ns/pid", p);
if (exists(buffer)) {
rc = readlink(buffer, proc_ns, sizeof(proc_ns));
if (rc <= 0)
proc_ns[0] = '\0';
}
free(buffer);
if (strlen(my_ns) && strlen (proc_ns) && strcmp(my_ns, proc_ns))
continue;
if (uid) {
snprintf(buffer, sizeof(buffer), "/proc/%d", p);
if (stat(buffer, &sb) != 0 || sb.st_uid != uid)
xasprintf(&buffer, "/proc/%d", p);
if (stat(buffer, &sb) != 0 || sb.st_uid != uid) {
free(buffer);
continue;
}
free(buffer);
}
if (exec && !pid_is_exec(p, exec))
continue;
@@ -150,9 +177,10 @@ rc_find_pids(const char *exec, const char *const *argv, uid_t uid, pid_t pid)
continue;
/* If this is an OpenVZ host, filter out container processes */
if (openvz_host) {
snprintf(buffer, sizeof(buffer), "/proc/%d/status", p);
xasprintf(&buffer, "/proc/%d/status", p);
if (exists(buffer)) {
fp = fopen(buffer, "r");
free(buffer);
if (! fp)
continue;
while (! feof(fp)) {
@@ -296,12 +324,13 @@ _match_daemon(const char *path, const char *file, RC_STRINGLIST *match)
{
char *line = NULL;
size_t len = 0;
char ffile[PATH_MAX];
char *ffile = NULL;
FILE *fp;
RC_STRING *m;
snprintf(ffile, sizeof(ffile), "%s/%s", path, file);
xasprintf(&ffile, "%s/%s", path, file);
fp = fopen(ffile, "r");
free(ffile);
if (!fp)
return false;
@@ -327,29 +356,22 @@ _match_list(const char *exec, const char *const *argv, const char *pidfile)
{
RC_STRINGLIST *match = rc_stringlist_new();
int i = 0;
size_t l;
char *m;
if (exec) {
l = strlen(exec) + 6;
m = xmalloc(sizeof(char) * l);
snprintf(m, l, "exec=%s", exec);
xasprintf(&m, "exec=%s", exec);
rc_stringlist_add(match, m);
free(m);
}
while (argv && argv[i]) {
l = strlen(*argv) + strlen("argv_=") + 16;
m = xmalloc(sizeof(char) * l);
snprintf(m, l, "argv_0=%s", argv[i++]);
xasprintf(&m, "argv_0=%s", argv[i++]);
rc_stringlist_add(match, m);
free(m);
}
if (pidfile) {
l = strlen(pidfile) + 9;
m = xmalloc(sizeof(char) * l);
snprintf(m, l, "pidfile=%s", pidfile);
xasprintf(&m, "pidfile=%s", pidfile);
rc_stringlist_add(match, m);
free(m);
}
@@ -362,8 +384,8 @@ rc_service_daemon_set(const char *service, const char *exec,
const char *const *argv,
const char *pidfile, bool started)
{
char dirpath[PATH_MAX];
char file[PATH_MAX];
char *dirpath = NULL;
char *file = NULL;
int nfiles = 0;
char oldfile[PATH_MAX] = { '\0' };
bool retval = false;
@@ -378,8 +400,7 @@ rc_service_daemon_set(const char *service, const char *exec,
return false;
}
snprintf(dirpath, sizeof(dirpath), RC_SVCDIR "/daemons/%s",
basename_c(service));
xasprintf(&dirpath, RC_SVCDIR "/daemons/%s", basename_c(service));
/* Regardless, erase any existing daemon info */
if ((dp = opendir(dirpath))) {
@@ -388,8 +409,7 @@ rc_service_daemon_set(const char *service, const char *exec,
if (d->d_name[0] == '.')
continue;
snprintf(file, sizeof(file), "%s/%s",
dirpath, d->d_name);
xasprintf(&file, "%s/%s", dirpath, d->d_name);
nfiles++;
if (!*oldfile) {
@@ -402,6 +422,7 @@ rc_service_daemon_set(const char *service, const char *exec,
rename(file, oldfile);
strlcpy(oldfile, file, sizeof(oldfile));
}
free(file);
}
closedir(dp);
rc_stringlist_free(match);
@@ -410,8 +431,7 @@ rc_service_daemon_set(const char *service, const char *exec,
/* Now store our daemon info */
if (started) {
if (mkdir(dirpath, 0755) == 0 || errno == EEXIST) {
snprintf(file, sizeof(file), "%s/%03d",
dirpath, nfiles + 1);
xasprintf(&file, "%s/%03d", dirpath, nfiles + 1);
if ((fp = fopen(file, "w"))) {
fprintf(fp, "exec=");
if (exec)
@@ -427,10 +447,12 @@ rc_service_daemon_set(const char *service, const char *exec,
fclose(fp);
retval = true;
}
free(file);
}
} else
retval = true;
free(dirpath);
return retval;
}
librc_hidden_def(rc_service_daemon_set)
@@ -439,8 +461,8 @@ bool
rc_service_started_daemon(const char *service,
const char *exec, const char *const *argv, int indx)
{
char dirpath[PATH_MAX];
char file[16];
char *dirpath = NULL;
char *file = NULL;
RC_STRINGLIST *match;
bool retval = false;
DIR *dp;
@@ -449,13 +471,13 @@ rc_service_started_daemon(const char *service,
if (!service || !exec)
return false;
snprintf(dirpath, sizeof(dirpath), RC_SVCDIR "/daemons/%s",
basename_c(service));
xasprintf(&dirpath, RC_SVCDIR "/daemons/%s", basename_c(service));
match = _match_list(exec, argv, NULL);
if (indx > 0) {
snprintf(file, sizeof(file), "%03d", indx);
xasprintf(&file, "%03d", indx);
retval = _match_daemon(dirpath, file, match);
free(file);
} else {
if ((dp = opendir(dirpath))) {
while ((d = readdir(dp))) {
@@ -470,6 +492,7 @@ rc_service_started_daemon(const char *service,
}
rc_stringlist_free(match);
free(dirpath);
return retval;
}
librc_hidden_def(rc_service_started_daemon)

View File

@@ -542,52 +542,41 @@ rc_deptree_order(const RC_DEPTREE *deptree, const char *runlevel, int options)
}
librc_hidden_def(rc_deptree_order)
/* Given a time, recurse the target path to find out if there are
any older (or newer) files. If false, sets the time to the
oldest (or newest) found.
*/
static bool
mtime_check(const char *source, const char *target, bool newer,
deep_mtime_check(const char *target, bool newer,
time_t *rel, char *file)
{
struct stat buf;
time_t mtime;
bool retval = true;
DIR *dp;
struct dirent *d;
char path[PATH_MAX];
int serrno = errno;
/* We have to exist */
if (stat(source, &buf) != 0)
return false;
mtime = buf.st_mtime;
/* If target does not exist, return true to mimic shell test */
if (stat(target, &buf) != 0)
return true;
if (newer) {
if (mtime < buf.st_mtime) {
if (rel == NULL)
return false;
if (*rel < buf.st_mtime) {
retval = false;
}
if (rel != NULL) {
if (*rel < buf.st_mtime) {
if (file)
strlcpy(file, target, PATH_MAX);
*rel = buf.st_mtime;
}
if (file)
strlcpy(file, target, PATH_MAX);
*rel = buf.st_mtime;
}
} else {
if (mtime > buf.st_mtime) {
if (rel == NULL)
return false;
if (*rel > buf.st_mtime) {
retval = false;
}
if (rel != NULL) {
if (*rel > buf.st_mtime) {
if (file)
strlcpy(file, target, PATH_MAX);
*rel = buf.st_mtime;
}
if (file)
strlcpy(file, target, PATH_MAX);
*rel = buf.st_mtime;
}
}
@@ -602,16 +591,38 @@ mtime_check(const char *source, const char *target, bool newer,
if (d->d_name[0] == '.')
continue;
snprintf(path, sizeof(path), "%s/%s", target, d->d_name);
if (!mtime_check(source, path, newer, rel, file)) {
if (!deep_mtime_check(path, newer, rel, file)) {
retval = false;
if (rel == NULL)
break;
}
}
closedir(dp);
return retval;
}
/* Recursively check if target is older/newer than source.
* If false, return the filename and most different time (if
* the return value arguments are non-null).
*/
static bool
mtime_check(const char *source, const char *target, bool newer,
time_t *rel, char *file)
{
struct stat buf;
time_t mtime;
bool retval = true;
/* We have to exist */
if (stat(source, &buf) != 0)
return false;
mtime = buf.st_mtime;
retval = deep_mtime_check(target,newer,&mtime,file);
if (rel) {
*rel = mtime;
}
return retval;
}
bool
rc_newer_than(const char *source, const char *target,
time_t *newest, char *file)
@@ -670,6 +681,8 @@ rc_deptree_update_needed(time_t *newest, char *file)
RC_STRINGLIST *config;
RC_STRING *s;
int i;
struct stat buf;
time_t mtime;
/* Create base directories if needed */
for (i = 0; depdirs[i]; i++)
@@ -677,42 +690,48 @@ rc_deptree_update_needed(time_t *newest, char *file)
fprintf(stderr, "mkdir `%s': %s\n", depdirs[i], strerror(errno));
/* Quick test to see if anything we use has changed and we have
* data in our deptree */
if (!existss(RC_DEPTREE_CACHE))
return true;
if (!rc_newer_than(RC_DEPTREE_CACHE, RC_INITDIR, newest, file))
return true;
if (!rc_newer_than(RC_DEPTREE_CACHE, RC_CONFDIR, newest, file))
return true;
* data in our deptree. */
if (stat(RC_DEPTREE_CACHE, &buf) == 0) {
mtime = buf.st_mtime;
} else {
/* No previous cache found.
* We still run the scan, in case of clock skew; we still need to return
* the newest time.
*/
newer = true;
mtime = time(NULL);
}
newer |= !deep_mtime_check(RC_INITDIR,true,&mtime,file);
newer |= !deep_mtime_check(RC_CONFDIR,true,&mtime,file);
#ifdef RC_PKG_INITDIR
if (!rc_newer_than(RC_DEPTREE_CACHE, RC_PKG_INITDIR, newest, file))
return true;
newer |= !deep_mtime_check(RC_PKG_INITDIR,true,&mtime,file);
#endif
#ifdef RC_PKG_CONFDIR
if (!rc_newer_than(RC_DEPTREE_CACHE, RC_PKG_CONFDIR, newest, file))
return true;
newer |= !deep_mtime_check(RC_PKG_CONFDIR,true,&mtime,file);
#endif
#ifdef RC_LOCAL_INITDIR
if (!rc_newer_than(RC_DEPTREE_CACHE, RC_LOCAL_INITDIR, newest, file))
return true;
#ifdef RC_LOCAL_INITDIRs
newer |= !deep_mtime_check(RC_LOCAL_INITDIR,true,&mtime,file);
#endif
#ifdef RC_LOCAL_CONFDIR
if (!rc_newer_than(RC_DEPTREE_CACHE, RC_LOCAL_CONFDIR, newest, file))
return true;
newer |= !deep_mtime_check(RC_LOCAL_CONFDIR,true,&mtime,file);
#endif
if (!rc_newer_than(RC_DEPTREE_CACHE, RC_CONF, newest, file))
return true;
newer |= !deep_mtime_check(RC_CONF,true,&mtime,file);
/* Some init scripts dependencies change depending on config files
* outside of baselayout, like syslog-ng, so we check those too. */
config = rc_config_list(RC_DEPCONFIG);
TAILQ_FOREACH(s, config, entries) {
if (!rc_newer_than(RC_DEPTREE_CACHE, s->value, newest, file)) {
newer = true;
break;
}
newer |= !deep_mtime_check(s->value, true, &mtime, file);
}
rc_stringlist_free(config);
/* Return newest file time, if requested */
if ((newer) && (newest != NULL)) {
*newest = mtime;
}
return newer;
}
librc_hidden_def(rc_deptree_update_needed)

View File

@@ -237,13 +237,9 @@ static void rc_config_set_value(RC_STRINGLIST *config, char *value)
if (token[i] == '\n')
token[i] = 0;
i = strlen(entry) + strlen(token) + 2;
newline = xmalloc(sizeof(char) * i);
snprintf(newline, i, "%s=%s", entry, token);
xasprintf(&newline, "%s=%s", entry, token);
} else {
i = strlen(entry) + 2;
newline = xmalloc(sizeof(char) * i);
snprintf(newline, i, "%s=", entry);
xasprintf(&newline, "%s=", entry);
}
replaced = false;
@@ -300,8 +296,7 @@ static RC_STRINGLIST *rc_config_kcl(RC_STRINGLIST *config)
if (value != NULL) {
len = varlen + strlen(value) + 2;
tmp = xmalloc(sizeof(char) * len);
snprintf(tmp, len, "%s=%s", override->value, value);
xasprintf(&tmp, "%s=%s", override->value, value);
}
/*

View File

@@ -50,6 +50,7 @@ static const rc_service_state_name_t rc_service_state_names[] = {
{ RC_SERVICE_HOTPLUGGED, "hotplugged" },
{ RC_SERVICE_FAILED, "failed" },
{ RC_SERVICE_SCHEDULED, "scheduled"},
{ RC_SERVICE_CRASHED, "crashed"},
{ 0, NULL}
};
@@ -848,6 +849,10 @@ rc_service_state(const char *service)
}
}
if (state & RC_SERVICE_STARTED) {
if (rc_service_daemons_crashed(service) && errno != EACCES)
state |= RC_SERVICE_CRASHED;
}
if (state & RC_SERVICE_STOPPED) {
dirs = ls_dir(RC_SVCDIR "/scheduled", 0);
TAILQ_FOREACH(dir, dirs, entries) {
@@ -894,12 +899,15 @@ rc_service_value_set(const char *service, const char *option,
return false;
snprintf(p, sizeof(file) - (p - file), "/%s", option);
if (!(fp = fopen(file, "w")))
return false;
if (value)
if (value) {
if (!(fp = fopen(file, "w")))
return false;
fprintf(fp, "%s", value);
fclose(fp);
return true;
fclose(fp);
} else {
unlink(file);
}
return true;
}
librc_hidden_def(rc_service_value_set)

View File

@@ -188,7 +188,8 @@ typedef enum
/* Optional states service could also be in */
RC_SERVICE_FAILED = 0x0200,
RC_SERVICE_SCHEDULED = 0x0400,
RC_SERVICE_WASINACTIVE = 0x0800
RC_SERVICE_WASINACTIVE = 0x0800,
RC_SERVICE_CRASHED = 0x1000,
} RC_SERVICE;
/*! Add the service to the runlevel

1
src/rc/.gitignore vendored
View File

@@ -56,6 +56,7 @@ mark_service_inactive
mark_service_wasinactive
mark_service_hotplugged
mark_service_failed
mark_service_crashed
rc-abort
rc
openrc

View File

@@ -5,8 +5,8 @@ include ${MK}/os.mk
SRCS= checkpath.c do_e.c do_mark_service.c do_service.c \
do_value.c fstabinfo.c is_newer_than.c is_older_than.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 \
rc-depend.c rc-logger.c rc-misc.c rc-pipes.c \
rc-plugin.c rc-service.c rc-status.c rc-update.c \
shell_var.c start-stop-daemon.c supervise-daemon.c swclock.c _usage.c
ifeq (${MKSELINUX},yes)
@@ -14,7 +14,7 @@ SRCS+= rc-selinux.c
endif
ifeq (${OS},Linux)
SRCS+= kill_all.c openrc-init.c openrc-shutdown.c rc-wtmp.c
SRCS+= kill_all.c openrc-init.c openrc-shutdown.c broadcast.c rc-wtmp.c
endif
CLEANFILES= version.h rc-selinux.o
@@ -24,7 +24,7 @@ SBINDIR= ${PREFIX}/sbin
LINKDIR= ${LIBEXECDIR}
BINPROGS= rc-status
SBINPROGS = openrc openrc-run rc rc-service rc-update runscript service \
SBINPROGS = openrc openrc-run rc rc-service rc-update runscript \
start-stop-daemon supervise-daemon
RC_BINPROGS= einfon einfo ewarnn ewarn eerrorn eerror ebegin eend ewend \
eindent eoutdent esyslog eval_ecolors ewaitfile \
@@ -41,6 +41,7 @@ RC_SBINPROGS= mark_service_starting mark_service_started \
mark_service_stopping mark_service_stopped \
mark_service_inactive mark_service_wasinactive \
mark_service_hotplugged mark_service_failed \
mark_service_crashed \
rc-abort swclock
ifeq (${OS},Linux)
@@ -123,7 +124,8 @@ is_older_than: is_older_than.o rc-misc.o
mark_service_starting mark_service_started \
mark_service_stopping mark_service_stopped \
mark_service_inactive mark_service_wasinactive \
mark_service_hotplugged mark_service_failed: do_mark_service.o rc-misc.o
mark_service_hotplugged mark_service_failed \
mark_service_crashed: do_mark_service.o rc-misc.o
${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDADD}
mountinfo: mountinfo.o _usage.o rc-misc.o
@@ -132,7 +134,7 @@ mountinfo: mountinfo.o _usage.o rc-misc.o
openrc rc: rc.o rc-logger.o rc-misc.o rc-plugin.o _usage.o
${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDADD}
openrc-shutdown: openrc-shutdown.o _usage.o rc-wtmp.o
openrc-shutdown: openrc-shutdown.o rc-misc.o _usage.o broadcast.o rc-wtmp.o
${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDADD}
openrc-run runscript: openrc-run.o _usage.o rc-misc.o rc-plugin.o
@@ -150,16 +152,16 @@ rc-depend: rc-depend.o _usage.o rc-misc.o
rc-status: rc-status.o _usage.o rc-misc.o
${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDADD}
rc-service service: rc-service.o _usage.o rc-misc.o
rc-service: rc-service.o _usage.o rc-misc.o
${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDADD}
rc-update: rc-update.o _usage.o rc-misc.o
${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDADD}
start-stop-daemon: start-stop-daemon.o _usage.o rc-misc.o rc-schedules.o
start-stop-daemon: start-stop-daemon.o _usage.o rc-misc.o rc-pipes.o rc-schedules.o
${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDADD}
supervise-daemon: supervise-daemon.o _usage.o rc-misc.o rc-schedules.o
supervise-daemon: supervise-daemon.o _usage.o rc-misc.o rc-plugin.o rc-schedules.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

209
src/rc/broadcast.c Normal file
View File

@@ -0,0 +1,209 @@
/*
* broadcast.c
* broadcast a message to every logged in user
*/
/*
* Copyright 2018 Sony Interactive Entertainment Inc.
*
* 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.
*/
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/sysmacros.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <stdio.h>
#include <utmpx.h>
#include <pwd.h>
#include <fcntl.h>
#include <signal.h>
#include <setjmp.h>
#include <paths.h>
#include <sys/utsname.h>
#include "broadcast.h"
#include "helpers.h"
#ifndef _PATH_DEV
# define _PATH_DEV "/dev/"
#endif
#ifndef UT_LINESIZE
#define UT_LINESIZE __UT_LINESIZE
#endif
static sigjmp_buf jbuf;
/*
* Alarm handler
*/
/*ARGSUSED*/
# ifdef __GNUC__
static void handler(int arg __attribute__((unused)))
# else
static void handler(int arg)
# endif
{
siglongjmp(jbuf, 1);
}
static void getuidtty(char **userp, char **ttyp)
{
struct passwd *pwd;
uid_t uid;
char *tty;
static char uidbuf[32];
static char ttynm[UT_LINESIZE + 4];
uid = getuid();
if ((pwd = getpwuid(uid)) != NULL) {
uidbuf[0] = 0;
strncat(uidbuf, pwd->pw_name, sizeof(uidbuf) - 1);
} else {
if (uid)
sprintf(uidbuf, "uid %d", (int) uid);
else
sprintf(uidbuf, "root");
}
if ((tty = ttyname(0)) != NULL) {
const size_t plen = strlen(_PATH_DEV);
if (strncmp(tty, _PATH_DEV, plen) == 0) {
tty += plen;
if (tty[0] == '/')
tty++;
}
snprintf(ttynm, sizeof(ttynm), "(%.*s) ",
UT_LINESIZE, tty);
} else
ttynm[0] = 0;
*userp = uidbuf;
*ttyp = ttynm;
}
/*
* Check whether the given filename looks like a tty device.
*/
static int file_isatty(const char *fname)
{
struct stat st;
int major;
if (stat(fname, &st) < 0)
return 0;
if (st.st_nlink != 1 || !S_ISCHR(st.st_mode))
return 0;
/*
* It would be an impossible task to list all major/minors
* of tty devices here, so we just exclude the obvious
* majors of which just opening has side-effects:
* printers and tapes.
*/
major = major(st.st_dev);
if (major == 1 || major == 2 || major == 6 || major == 9 ||
major == 12 || major == 16 || major == 21 || major == 27 ||
major == 37 || major == 96 || major == 97 || major == 206 ||
major == 230)
return 0;
return 1;
}
/*
* broadcast function.
*/
void broadcast(char *text)
{
char *tty;
char *user;
struct utsname name;
time_t t;
char *date;
char *p;
char *line = NULL;
struct sigaction sa;
int fd;
FILE *tp;
int flags;
char *term = NULL;
struct utmpx *utmp;
getuidtty(&user, &tty);
/*
* Get and report current hostname, to make it easier to find out
* which machine is being shut down.
*/
uname(&name);
/* Get the time */
time(&t);
date = ctime(&t);
p = strchr(date, '\n');
if (p)
*p = 0;
xasprintf(&line, "\007\r\nBroadcast message from %s@%s %s(%s):\r\n\r\n",
user, name.nodename, tty, date);
/*
* Fork to avoid hanging in a write()
*/
if (fork() != 0)
return;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = handler;
sigemptyset(&sa.sa_mask);
sigaction(SIGALRM, &sa, NULL);
setutxent();
while ((utmp = getutxent()) != NULL) {
if (utmp->ut_type != USER_PROCESS || utmp->ut_user[0] == 0)
continue;
if (strncmp(utmp->ut_line, _PATH_DEV, strlen(_PATH_DEV)) == 0)
xasprintf(&term, "%s", utmp->ut_line);
else
xasprintf(&term, "%s%s", _PATH_DEV, utmp->ut_line);
if (strstr(term, "/../")) {
free(term);
continue;
}
/*
* Open it non-delay
*/
if (sigsetjmp(jbuf, 1) == 0) {
alarm(2);
flags = O_WRONLY|O_NDELAY|O_NOCTTY;
if (file_isatty(term) && (fd = open(term, flags)) >= 0) {
if (isatty(fd) && (tp = fdopen(fd, "w")) != NULL) {
fputs(line, tp);
fputs(text, tp);
fflush(tp);
}
}
}
alarm(0);
if (fd >= 0)
close(fd);
if (tp != NULL)
fclose(tp);
free(term);
}
endutxent();
free(line);
exit(0);
}

16
src/rc/broadcast.h Normal file
View File

@@ -0,0 +1,16 @@
/*
* Copyright 2018 Sony Interactive Entertainment Inc.
*
* 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.
*/
#ifndef BROADCAST_H
#define BROADCAST_H
void broadcast(char *text);
#endif

View File

@@ -73,25 +73,32 @@ static int do_check(char *path, uid_t uid, gid_t gid, mode_t mode,
inode_t type, bool trunc, bool chowner, bool selinux_on)
{
struct stat st;
int fd, flags;
int fd;
int flags;
int r;
int readfd;
int readflags;
int u;
memset(&st, 0, sizeof(st));
if (lstat(path, &st) || trunc) {
flags = O_CREAT|O_NDELAY|O_WRONLY|O_NOCTTY;
readflags = O_NDELAY|O_NOCTTY|O_RDONLY;
#ifdef O_CLOEXEC
flags |= O_CLOEXEC;
readflags |= O_CLOEXEC;
#endif
#ifdef O_NOFOLLOW
flags |= O_NOFOLLOW;
readflags |= O_NOFOLLOW;
#endif
if (trunc)
flags |= O_TRUNC;
readfd = open(path, readflags);
if (readfd == -1 || (type == inode_file && trunc)) {
if (type == inode_file) {
einfo("%s: creating file", path);
if (!mode) /* 664 */
mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH;
flags = O_CREAT|O_NDELAY|O_WRONLY|O_NOCTTY;
#ifdef O_CLOEXEC
flags |= O_CLOEXEC;
#endif
#ifdef O_NOFOLLOW
flags |= O_NOFOLLOW;
#endif
if (trunc)
flags |= O_TRUNC;
u = umask(0);
fd = open(path, flags, mode);
umask(u);
@@ -99,7 +106,9 @@ static int do_check(char *path, uid_t uid, gid_t gid, mode_t mode,
eerror("%s: open: %s", applet, strerror(errno));
return -1;
}
close (fd);
if (readfd != -1 && trunc)
close(readfd);
readfd = fd;
} else if (type == inode_dir) {
einfo("%s: creating directory", path);
if (!mode) /* 775 */
@@ -113,7 +122,12 @@ static int do_check(char *path, uid_t uid, gid_t gid, mode_t mode,
strerror (errno));
return -1;
}
mode = 0;
readfd = open(path, readflags);
if (readfd == -1) {
eerror("%s: unable to open directory: %s", applet,
strerror(errno));
return -1;
}
} else if (type == inode_fifo) {
einfo("%s: creating fifo", path);
if (!mode) /* 600 */
@@ -126,56 +140,76 @@ static int do_check(char *path, uid_t uid, gid_t gid, mode_t mode,
strerror (errno));
return -1;
}
readfd = open(path, readflags);
if (readfd == -1) {
eerror("%s: unable to open fifo: %s", applet,
strerror(errno));
return -1;
}
}
} else {
}
if (fstat(readfd, &st) != -1) {
if (type != inode_dir && S_ISDIR(st.st_mode)) {
eerror("%s: is a directory", path);
close(readfd);
return 1;
}
if (type != inode_file && S_ISREG(st.st_mode)) {
eerror("%s: is a file", path);
close(readfd);
return 1;
}
if (type != inode_fifo && S_ISFIFO(st.st_mode)) {
eerror("%s: is a fifo", path);
close(readfd);
return -1;
}
}
if (mode && (st.st_mode & 0777) != mode) {
if ((type != inode_dir) && (st.st_nlink > 1)) {
eerror("%s: chmod: %s %s", applet, "Too many hard links to", path);
return -1;
if (mode && (st.st_mode & 0777) != mode) {
if ((type != inode_dir) && (st.st_nlink > 1)) {
eerror("%s: chmod: %s %s", applet, "Too many hard links to", path);
close(readfd);
return -1;
}
if (S_ISLNK(st.st_mode)) {
eerror("%s: chmod: %s %s", applet, path, " is a symbolic link");
close(readfd);
return -1;
}
einfo("%s: correcting mode", path);
if (fchmod(readfd, mode)) {
eerror("%s: chmod: %s", applet, strerror(errno));
close(readfd);
return -1;
}
}
if (S_ISLNK(st.st_mode)) {
eerror("%s: chmod: %s %s", applet, path, " is a symbolic link");
return -1;
}
einfo("%s: correcting mode", path);
if (chmod(path, mode)) {
eerror("%s: chmod: %s", applet, strerror(errno));
return -1;
}
}
if (chowner && (st.st_uid != uid || st.st_gid != gid)) {
if ((type != inode_dir) && (st.st_nlink > 1)) {
eerror("%s: chown: %s %s", applet, "Too many hard links to", path);
return -1;
}
if (S_ISLNK(st.st_mode)) {
eerror("%s: chown: %s %s", applet, path, " is a symbolic link");
return -1;
}
einfo("%s: correcting owner", path);
if (chown(path, uid, gid)) {
eerror("%s: chown: %s", applet, strerror(errno));
return -1;
if (chowner && (st.st_uid != uid || st.st_gid != gid)) {
if ((type != inode_dir) && (st.st_nlink > 1)) {
eerror("%s: chown: %s %s", applet, "Too many hard links to", path);
close(readfd);
return -1;
}
if (S_ISLNK(st.st_mode)) {
eerror("%s: chown: %s %s", applet, path, " is a symbolic link");
close(readfd);
return -1;
}
einfo("%s: correcting owner", path);
if (fchown(readfd, uid, gid)) {
eerror("%s: chown: %s", applet, strerror(errno));
close(readfd);
return -1;
}
}
if (selinux_on)
selinux_util_label(path);
} else {
eerror("fstat: %s: %s", path, strerror(errno));
close(readfd);
return -1;
}
if (selinux_on)
selinux_util_label(path);
close(readfd);
return 0;
}
@@ -235,11 +269,13 @@ int main(int argc, char **argv)
switch (opt) {
case 'D':
trunc = true;
/* falls through */
case 'd':
type = inode_dir;
break;
case 'F':
trunc = true;
/* falls through */
case 'f':
type = inode_file;
break;

View File

@@ -68,9 +68,7 @@ int main(int argc, char **argv)
ok = rc_service_started_daemon(service, exec, NULL, idx);
} else if (strcmp(applet, "service_crashed") == 0) {
ok = (_rc_can_find_pids() &&
rc_service_daemons_crashed(service) &&
errno != EACCES);
ok = ( rc_service_daemons_crashed(service) && errno != EACCES);
} else
eerrorx("%s: unknown applet", applet);

View File

@@ -141,7 +141,7 @@ do_mount(struct ENT *ent, bool remount)
/* NOTREACHED */
case 0:
execvp(argv[0], argv);
eerror("%s: execv: %s", applet, strerror(errno));
eerror("%s: execvp: %s", applet, strerror(errno));
_exit(EXIT_FAILURE);
/* NOTREACHED */
default:

View File

@@ -58,14 +58,14 @@ static int mount_proc(void)
if (exists("/proc/version"))
return 0;
pid = fork();
switch(pid) {
switch (pid) {
case -1:
syslog(LOG_ERR, "Unable to fork");
return -1;
break;
case 0:
/* attempt to mount /proc */
execl("mount", "mount", "-t", "proc", "proc", "/proc", NULL);
execlp("mount", "mount", "-t", "proc", "proc", "/proc", NULL);
syslog(LOG_ERR, "Unable to execute mount");
exit(1);
break;
@@ -87,10 +87,11 @@ static int mount_proc(void)
static bool is_user_process(pid_t pid)
{
char buf[PATH_MAX+1];
char *buf = NULL;
FILE *fp;
char path[PATH_MAX+1];
char *path = NULL;
pid_t temp_pid;
size_t size;
bool user_process = true;
while (pid >0 && user_process) {
@@ -98,8 +99,9 @@ static bool is_user_process(pid_t pid)
user_process = false;
continue;
}
snprintf(path, sizeof(path), "/proc/%d/status", pid);
xasprintf(&path, "/proc/%d/status", pid);
fp = fopen(path, "r");
free(path);
/*
* if we could not open the file, the process disappeared, which
* leaves us no way to determine for sure whether it was a user
@@ -112,11 +114,14 @@ static bool is_user_process(pid_t pid)
}
temp_pid = -1;
while (! feof(fp)) {
buf[0] = 0;
if (fgets(buf, sizeof(buf), fp))
buf = NULL;
if (getline(&buf, &size, fp) != -1) {
sscanf(buf, "PPid: %d", &temp_pid);
else
free(buf);
} else {
free(buf);
break;
}
}
fclose(fp);
if (temp_pid == -1) {
@@ -135,7 +140,7 @@ static int signal_processes(int sig, RC_STRINGLIST *omits, bool dryrun)
sigset_t oldsigs;
DIR *dir;
struct dirent *d;
char buf[PATH_MAX+1];
char *buf = NULL;
pid_t pid;
int sendcount = 0;
@@ -170,7 +175,11 @@ static int signal_processes(int sig, RC_STRINGLIST *omits, bool dryrun)
continue;
/* Is this a process we have been requested to omit? */
sprintf(buf, "%d", pid);
if (buf) {
free(buf);
buf = NULL;
}
xasprintf(&buf, "%d", pid);
if (rc_stringlist_find(omits, buf))
continue;
@@ -239,7 +248,7 @@ int main(int argc, char **argv)
usage(EXIT_FAILURE);
}
}
openlog(applet, LOG_CONS|LOG_PID, LOG_DAEMON);
if (mount_proc() != 0) {
rc_stringlist_free(omits);

View File

@@ -248,7 +248,6 @@ find_mounts(struct args *args)
struct opt *o;
int netdev;
char *tmp;
size_t l;
if ((nmnts = getmntinfo(&mnts, MNT_NOWAIT)) == 0)
eerrorx("getmntinfo: %s", strerror (errno));
@@ -264,11 +263,7 @@ find_mounts(struct args *args)
if (! options)
options = xstrdup(o->o_name);
else {
l = strlen(options) +
strlen(o->o_name) + 2;
tmp = xmalloc(sizeof (char) * l);
snprintf(tmp, l, "%s,%s", options,
o->o_name);
xasprintf(&tmp, "%s,%s", options, o->o_name);
free(options);
options = tmp;
}
@@ -315,6 +310,7 @@ find_mounts(struct args *args)
{
FILE *fp;
char *buffer;
size_t size;
char *p;
char *from;
char *to;
@@ -329,8 +325,8 @@ find_mounts(struct args *args)
list = rc_stringlist_new();
buffer = xmalloc(sizeof(char) * PATH_MAX * 3);
while (fgets(buffer, PATH_MAX * 3, fp)) {
buffer = NULL;
while (getline(&buffer, &size, fp) != -1) {
netdev = -1;
p = buffer;
from = strsep(&p, " ");
@@ -346,6 +342,8 @@ find_mounts(struct args *args)
}
process_mount(list, args, from, to, fst, opts, netdev);
free(buffer);
buffer = NULL;
}
free(buffer);
fclose(fp);
@@ -380,7 +378,7 @@ int main(int argc, char **argv)
regex_t *skip_point_regex = NULL;
RC_STRINGLIST *nodes;
RC_STRING *s;
char real_path[PATH_MAX + 1];
char *real_path = NULL;
int opt;
int result;
char *this_path;
@@ -450,9 +448,12 @@ int main(int argc, char **argv)
eerrorx("%s: `%s' is not a mount point",
argv[0], argv[optind]);
this_path = argv[optind++];
if (realpath(this_path, real_path))
real_path = realpath(this_path, NULL);
if (real_path)
this_path = real_path;
rc_stringlist_add(args.mounts, this_path);
free(real_path);
real_path = NULL;
}
nodes = find_mounts(&args);
rc_stringlist_free(args.mounts);

View File

@@ -24,6 +24,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
@@ -35,6 +36,7 @@
#include "rc-wtmp.h"
#include "version.h"
static const char *path_default = "/sbin:/usr/sbin:/bin:/usr/bin";
static const char *rc_default_runlevel = "default";
static pid_t do_openrc(const char *runlevel)
@@ -43,7 +45,7 @@ static pid_t do_openrc(const char *runlevel)
sigset_t signals;
pid = fork();
switch(pid) {
switch (pid) {
case -1:
perror("fork");
break;
@@ -53,7 +55,7 @@ static pid_t do_openrc(const char *runlevel)
sigemptyset(&signals);
sigprocmask(SIG_SETMASK, &signals, NULL);
printf("Starting %s runlevel\n", runlevel);
execl("/sbin/openrc", "/sbin/openrc", runlevel, NULL);
execlp("openrc", "openrc", runlevel, NULL);
perror("exec");
break;
default:
@@ -88,19 +90,22 @@ static void init(const char *default_runlevel)
static void handle_reexec(char *my_name)
{
execl(my_name, my_name, "reexec", NULL);
execlp(my_name, my_name, "reexec", NULL);
return;
}
static void handle_shutdown(const char *runlevel, int cmd)
{
pid_t pid;
struct timespec ts;
pid = do_openrc(runlevel);
while (waitpid(pid, NULL, 0) != pid);
printf("Sending the final term signal\n");
kill(-1, SIGTERM);
sleep(3);
ts.tv_sec = 3;
ts.tv_nsec = 0;
nanosleep(&ts, NULL);
printf("Sending the final kill signal\n");
kill(-1, SIGKILL);
sync();
@@ -134,7 +139,7 @@ static void reap_zombies(void)
static void signal_handler(int sig)
{
switch(sig) {
switch (sig) {
case SIGINT:
handle_shutdown("reboot", RB_AUTOBOOT);
break;
@@ -183,6 +188,9 @@ int main(int argc, char **argv)
sigaction(SIGINT, &sa, NULL);
reboot(RB_DISABLE_CAD);
/* set default path */
setenv("PATH", path_default, 1);
if (! reexec)
init(default_runlevel);

View File

@@ -109,7 +109,7 @@ static void
handle_signal(int sig)
{
int serrno = errno;
char signame[10] = { '\0' };
char *signame = NULL;
struct winsize ws;
switch (sig) {
@@ -134,20 +134,22 @@ handle_signal(int sig)
break;
case SIGINT:
if (!signame[0])
snprintf(signame, sizeof(signame), "SIGINT");
if (!signame)
xasprintf(&signame, "SIGINT");
/* FALLTHROUGH */
case SIGTERM:
if (!signame[0])
snprintf(signame, sizeof(signame), "SIGTERM");
if (!signame)
xasprintf(&signame, "SIGTERM");
/* FALLTHROUGH */
case SIGQUIT:
if (!signame[0])
snprintf(signame, sizeof(signame), "SIGQUIT");
if (!signame)
xasprintf(&signame, "SIGQUIT");
/* Send the signal to our children too */
if (service_pid > 0)
kill(service_pid, sig);
eerrorx("%s: caught %s, aborting", applet, signame);
eerror("%s: caught %s, aborting", applet, signame);
free(signame);
exit(EXIT_FAILURE);
/* NOTREACHED */
default:
@@ -161,11 +163,12 @@ handle_signal(int sig)
static void
unhotplug()
{
char file[PATH_MAX];
char *file = NULL;
snprintf(file, sizeof(file), RC_SVCDIR "/hotplugged/%s", applet);
xasprintf(&file, RC_SVCDIR "/hotplugged/%s", applet);
if (exists(file) && unlink(file) != 0)
eerror("%s: unlink `%s': %s", applet, file, strerror(errno));
free(file);
}
static void
@@ -485,7 +488,7 @@ svc_exec(const char *arg1, const char *arg2)
static bool
svc_wait(const char *svc)
{
char file[PATH_MAX];
char *file = NULL;
int fd;
bool forever = false;
RC_STRINGLIST *keywords;
@@ -498,8 +501,7 @@ svc_wait(const char *svc)
forever = true;
rc_stringlist_free(keywords);
snprintf(file, sizeof(file), RC_SVCDIR "/exclusive/%s",
basename_c(svc));
xasprintf(&file, RC_SVCDIR "/exclusive/%s", basename_c(svc));
interval.tv_sec = 0;
interval.tv_nsec = WAIT_INTERVAL;
@@ -512,23 +514,29 @@ svc_wait(const char *svc)
if (fd != -1) {
if (flock(fd, LOCK_SH | LOCK_NB) == 0) {
close(fd);
free(file);
return true;
}
close(fd);
}
if (errno == ENOENT)
if (errno == ENOENT) {
free(file);
return true;
if (errno != EWOULDBLOCK)
eerrorx("%s: open `%s': %s", applet, file,
}
if (errno != EWOULDBLOCK) {
eerror("%s: open `%s': %s", applet, file,
strerror(errno));
free(file);
exit(EXIT_FAILURE);
}
if (nanosleep(&interval, NULL) == -1) {
if (errno != EINTR)
return false;
goto finish;
}
if (!forever) {
timespecsub(&timeout, &interval, &timeout);
if (timeout.tv_sec <= 0)
return false;
goto finish;
timespecsub(&warn, &interval, &warn);
if (warn.tv_sec <= 0) {
ewarn("%s: waiting for %s (%d seconds)",
@@ -538,6 +546,8 @@ svc_wait(const char *svc)
}
}
}
finish:
free(file);
return false;
}
@@ -1105,9 +1115,10 @@ int main(int argc, char **argv)
bool runscript = false;
int retval, opt, depoptions = RC_DEP_TRACE;
RC_STRING *svc;
char path[PATH_MAX], lnk[PATH_MAX];
char *path = NULL;
char *lnk = NULL;
char *dir, *save = NULL, *saveLnk = NULL;
char pidstr[10];
char *pidstr = NULL;
size_t l = 0, ll;
const char *file;
struct stat stbuf;
@@ -1134,12 +1145,14 @@ int main(int argc, char **argv)
* This works fine, provided that we ONLY allow multiplexed services
* to exist in the same directory as the master link.
* Also, the master link as to be a real file in the init dir. */
if (!realpath(argv[1], path)) {
path = realpath(argv[1], NULL);
if (!path) {
fprintf(stderr, "realpath: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
memset(lnk, 0, sizeof(lnk));
if (readlink(argv[1], lnk, sizeof(lnk)-1)) {
lnk = xmalloc(4096);
memset(lnk, 0, 4096);
if (readlink(argv[1], lnk, 4096)) {
dir = dirname(path);
if (strchr(lnk, '/')) {
save = xstrdup(dir);
@@ -1153,8 +1166,7 @@ int main(int argc, char **argv)
} else
file = basename_c(argv[1]);
ll = strlen(dir) + strlen(file) + 2;
service = xmalloc(ll);
snprintf(service, ll, "%s/%s", dir, file);
xasprintf(&service, "%s/%s", dir, file);
if (stat(service, &stbuf) != 0) {
free(service);
service = xstrdup(lnk);
@@ -1162,6 +1174,7 @@ int main(int argc, char **argv)
free(save);
free(saveLnk);
}
free(lnk);
if (!service)
service = xstrdup(path);
applet = basename_c(service);
@@ -1185,7 +1198,7 @@ int main(int argc, char **argv)
/* Set an env var so that we always know our pid regardless of any
subshells the init script may create so that our mark_service_*
functions can always instruct us of this change */
snprintf(pidstr, sizeof(pidstr), "%d", (int) getpid());
xasprintf(&pidstr, "%d", (int) getpid());
setenv("RC_OPENRC_PID", pidstr, 1);
/*
* RC_RUNSCRIPT_PID is deprecated, but we will keep it for a while
@@ -1255,6 +1268,9 @@ int main(int argc, char **argv)
case_RC_COMMON_GETOPT
}
if (rc_yesno(getenv("RC_NODEPS")))
deps = false;
/* If we're changing runlevels and not called by rc then we cannot
work with any dependencies */
if (deps && getenv("RC_PID") == NULL &&
@@ -1269,6 +1285,8 @@ int main(int argc, char **argv)
unsetenv("IN_BACKGROUND");
}
if (rc_yesno(getenv("IN_DRYRUN")))
dry_run = true;
if (rc_yesno(getenv("IN_HOTPLUG"))) {
if (!service_plugable())
eerrorx("%s: not allowed to be hotplugged", applet);

View File

@@ -25,20 +25,24 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/utsname.h>
#include "broadcast.h"
#include "einfo.h"
#include "rc.h"
#include "helpers.h"
#include "rc-misc.h"
#include "_usage.h"
#include "rc-wtmp.h"
const char *applet = NULL;
const char *extraopts = NULL;
const char *getoptstring = "dDHKpRrsw" getoptstring_COMMON;
const char *getoptstring = "cdDfFHKpRrsw" getoptstring_COMMON;
const struct option longopts[] = {
{ "cancel", no_argument, NULL, 'c'},
{ "no-write", no_argument, NULL, 'd'},
{ "dry-run", no_argument, NULL, 'D'},
{ "halt", no_argument, NULL, 'H'},
@@ -51,6 +55,7 @@ const struct option longopts[] = {
longopts_COMMON
};
const char * const longopts_help[] = {
"cancel a pending shutdown",
"do not write wtmp record",
"print actions instead of executing them",
"halt the system",
@@ -64,8 +69,12 @@ const char * const longopts_help[] = {
};
const char *usagestring = NULL;
const char *exclusive = "Select one of "
"--halt, --kexec, --poweroff, --reexec, --reboot, --single or --write-only";
"--cancel, --halt, --kexec, --poweroff, --reexec, --reboot, --single or \n"
"--write-only";
const char *nologin_file = RC_SYSCONFDIR"/nologin";
const char *shutdown_pid = "/run/openrc-shutdown.pid";
static bool do_cancel = false;
static bool do_dryrun = false;
static bool do_halt = false;
static bool do_kexec = false;
@@ -76,6 +85,40 @@ static bool do_single = false;
static bool do_wtmp = true;
static bool do_wtmp_only = false;
static void cancel_shutdown(void)
{
pid_t pid;
pid = get_pid(applet, shutdown_pid);
if (pid <= 0)
eerrorx("%s: Unable to cancel shutdown", applet);
if (kill(pid, SIGTERM) != -1)
einfo("%s: shutdown canceled", applet);
else
eerrorx("%s: Unable to cancel shutdown", applet);
}
/*
* Create the nologin file.
*/
static void create_nologin(int mins)
{
FILE *fp;
time_t t;
time(&t);
t += 60 * mins;
if ((fp = fopen(nologin_file, "w")) != NULL) {
fprintf(fp, "\rThe system is going down on %s\r\n", ctime(&t));
fclose(fp);
}
}
/*
* Send a command to our init
*/
static void send_cmd(const char *cmd)
{
FILE *fifo;
@@ -99,16 +142,59 @@ static void send_cmd(const char *cmd)
fclose(fifo);
}
/*
* sleep without being interrupted.
* The idea for this code came from sysvinit.
*/
static void sleep_no_interrupt(int seconds)
{
struct timespec duration;
struct timespec remaining;
duration.tv_sec = seconds;
duration.tv_nsec = 0;
while(nanosleep(&duration, &remaining) < 0 && errno == EINTR)
duration = remaining;
}
static void stop_shutdown(int sig)
{
/* use the sig parameter so the compiler will not complain */
if (sig == SIGINT)
;
unlink(nologin_file);
unlink(shutdown_pid);
einfo("Shutdown canceled");
exit(0);
}
int main(int argc, char **argv)
{
char *ch = NULL;
int opt;
int cmd_count = 0;
int hour = 0;
int min = 0;
int shutdown_delay = 0;
struct sigaction sa;
struct tm *lt;
time_t tv;
bool need_warning = false;
char *msg = NULL;
char *state = NULL;
char *time_arg = NULL;
FILE *fp;
applet = basename_c(argv[0]);
while ((opt = getopt_long(argc, argv, getoptstring,
longopts, (int *) 0)) != -1)
{
switch (opt) {
case 'c':
do_cancel = true;
cmd_count++;
break;
case 'd':
do_wtmp = false;
break;
@@ -117,14 +203,17 @@ int main(int argc, char **argv)
break;
case 'H':
do_halt = true;
xasprintf(&state, "%s", "halt");
cmd_count++;
break;
case 'K':
do_kexec = true;
xasprintf(&state, "%s", "reboot");
cmd_count++;
break;
case 'p':
do_poweroff = true;
xasprintf(&state, "%s", "power off");
cmd_count++;
break;
case 'R':
@@ -133,10 +222,12 @@ int main(int argc, char **argv)
break;
case 'r':
do_reboot = true;
xasprintf(&state, "%s", "reboot");
cmd_count++;
break;
case 's':
do_single = true;
xasprintf(&state, "%s", "go down for maintenance");
cmd_count++;
break;
case 'w':
@@ -146,12 +237,88 @@ int main(int argc, char **argv)
case_RC_COMMON_GETOPT
}
}
if (geteuid() != 0 && ! do_dryrun)
if (geteuid() != 0)
eerrorx("%s: you must be root\n", applet);
if (cmd_count != 1) {
eerror("%s: %s\n", applet, exclusive);
usage(EXIT_FAILURE);
}
if (do_cancel) {
cancel_shutdown();
exit(EXIT_SUCCESS);
} else if (do_reexec) {
send_cmd("reexec");
exit(EXIT_SUCCESS);
}
if (optind >= argc) {
eerror("%s: No shutdown time specified", applet);
usage(EXIT_FAILURE);
}
time_arg = argv[optind];
if (*time_arg == '+')
time_arg++;
if (strcasecmp(time_arg, "now") == 0)
strcpy(time_arg, "0");
for (ch=time_arg; *ch; ch++)
if ((*ch < '0' || *ch > '9') && *ch != ':') {
eerror("%s: invalid time %s", applet, time_arg);
usage(EXIT_FAILURE);
}
if (strchr(time_arg, ':')) {
if ((sscanf(time_arg, "%2d:%2d", &hour, &min) != 2) ||
(hour > 23) || (min > 59)) {
eerror("%s: invalid time %s", applet, time_arg);
usage(EXIT_FAILURE);
}
time(&tv);
lt = localtime(&tv);
shutdown_delay = (hour * 60 + min) - (lt->tm_hour * 60 + lt->tm_min);
if (shutdown_delay < 0)
shutdown_delay += 1440;
} else {
shutdown_delay = atoi(time_arg);
}
fp = fopen(shutdown_pid, "w");
if (!fp)
eerrorx("%s: fopen `%s': %s", applet, shutdown_pid, strerror(errno));
fprintf(fp, "%d\n", getpid());
fclose(fp);
openlog(applet, LOG_PID, LOG_DAEMON);
memset(&sa, 0, sizeof(sa));
sa.sa_handler = stop_shutdown;
sigemptyset(&sa.sa_mask);
sigaction(SIGINT, &sa, NULL);
sigaction(SIGTERM, &sa, NULL);
while (shutdown_delay > 0) {
need_warning = false;
if (shutdown_delay > 180)
need_warning = (shutdown_delay % 60 == 0);
else if (shutdown_delay > 60)
need_warning = (shutdown_delay % 30 == 0);
else if (shutdown_delay > 10)
need_warning = (shutdown_delay % 15 == 0);
else
need_warning = true;
if (shutdown_delay <= 5)
create_nologin(shutdown_delay);
if (need_warning) {
xasprintf(&msg, "\rThe system will %s in %d minutes\r\n",
state, shutdown_delay);
broadcast(msg);
free(msg);
}
sleep_no_interrupt(60);
shutdown_delay--;
}
xasprintf(&msg, "\rThe system will %s now\r\n", state);
broadcast(msg);
syslog(LOG_NOTICE, "The system will %s now", state);
unlink(nologin_file);
unlink(shutdown_pid);
if (do_halt)
send_cmd("halt");
else if (do_kexec)
@@ -160,11 +327,9 @@ int main(int argc, char **argv)
send_cmd("poweroff");
else if (do_reboot)
send_cmd("reboot");
else if (do_reexec)
send_cmd("reexec");
else if (do_wtmp_only)
log_wtmp("shutdown", "~~", 0, RUN_LVL, "~~");
else if (do_single)
send_cmd("single");
else if (do_wtmp_only)
log_wtmp("shutdown", "~~", 0, RUN_LVL, "~~");
return 0;
}

View File

@@ -87,6 +87,8 @@ write_log(int logfd, const char *buffer, size_t bytes)
}
if (!in_escape) {
if (!isprint((int) *p) && *p != '\n')
goto cont;
if (write(logfd, p++, 1) == -1)
eerror("write: %s", strerror(errno));
continue;

View File

@@ -51,7 +51,8 @@ rc_conf_yesno(const char *setting)
static const char *const env_whitelist[] = {
"EERROR_QUIET", "EINFO_QUIET",
"IN_BACKGROUND", "IN_HOTPLUG",
"IN_BACKGROUND", "IN_DRYRUN", "IN_HOTPLUG",
"RC_DEBUG", "RC_NODEPS",
"LANG", "LC_MESSAGES", "TERM",
"EINFO_COLOR", "EINFO_VERBOSE",
NULL
@@ -131,7 +132,8 @@ env_config(void)
char *npp;
char *tok;
const char *sys = rc_sys();
char buffer[PATH_MAX];
char *buffer = NULL;
size_t size = 0;
/* Ensure our PATH is prefixed with the system locations first
for a little extra security */
@@ -170,8 +172,7 @@ env_config(void)
free(e);
if ((fp = fopen(RC_KRUNLEVEL, "r"))) {
memset(buffer, 0, sizeof (buffer));
if (fgets(buffer, sizeof (buffer), fp)) {
if (getline(&buffer, &size, fp) != -1) {
l = strlen (buffer) - 1;
if (buffer[l] == '\n')
buffer[l] = 0;
@@ -181,6 +182,7 @@ env_config(void)
} else
setenv("RC_DEFAULTLEVEL", RC_LEVEL_DEFAULT, 1);
free(buffer);
if (sys)
setenv("RC_SYS", sys, 1);
@@ -217,14 +219,27 @@ signal_setup(int sig, void (*handler)(int))
return sigaction(sig, &sa, NULL);
}
int
signal_setup_restart(int sig, void (*handler)(int))
{
struct sigaction sa;
memset(&sa, 0, sizeof (sa));
sigemptyset(&sa.sa_mask);
sa.sa_handler = handler;
sa.sa_flags = SA_RESTART;
return sigaction(sig, &sa, NULL);
}
int
svc_lock(const char *applet)
{
char file[PATH_MAX];
char *file = NULL;
int fd;
snprintf(file, sizeof(file), RC_SVCDIR "/exclusive/%s", applet);
xasprintf(&file, RC_SVCDIR "/exclusive/%s", applet);
fd = open(file, O_WRONLY | O_CREAT | O_NONBLOCK, 0664);
free(file);
if (fd == -1)
return -1;
if (flock(fd, LOCK_EX | LOCK_NB) == -1) {
@@ -238,11 +253,12 @@ svc_lock(const char *applet)
int
svc_unlock(const char *applet, int fd)
{
char file[PATH_MAX];
char *file = NULL;
snprintf(file, sizeof(file), RC_SVCDIR "/exclusive/%s", applet);
xasprintf(&file, RC_SVCDIR "/exclusive/%s", applet);
close(fd);
unlink(file);
free(file);
return -1;
}
@@ -346,7 +362,7 @@ RC_DEPTREE * _rc_deptree_load(int force, int *regen)
int serrno = errno;
int merrno;
time_t t;
char file[PATH_MAX];
char *file = NULL;
struct stat st;
struct utimbuf ut;
FILE *fp;
@@ -368,7 +384,10 @@ RC_DEPTREE * _rc_deptree_load(int force, int *regen)
eend (retval, "Failed to update the dependency tree");
if (retval == 0) {
stat(RC_DEPTREE_CACHE, &st);
if (stat(RC_DEPTREE_CACHE, &st) != 0) {
eerror("stat(%s): %s", RC_DEPTREE_CACHE, strerror(errno));
return NULL;
}
if (st.st_mtime < t) {
eerror("Clock skew detected with `%s'", file);
eerrorn("Adjusting mtime of `" RC_DEPTREE_CACHE
@@ -392,34 +411,6 @@ RC_DEPTREE * _rc_deptree_load(int force, int *regen)
return rc_deptree_load();
}
bool _rc_can_find_pids(void)
{
RC_PIDLIST *pids;
RC_PID *pid;
RC_PID *pid2;
bool retval = false;
if (geteuid() == 0)
return true;
/* If we cannot see process 1, then we don't test to see if
* services crashed or not */
pids = rc_find_pids(NULL, NULL, 0, 1);
if (pids) {
pid = LIST_FIRST(pids);
if (pid) {
retval = true;
while (pid) {
pid2 = LIST_NEXT(pid, entries);
free(pid);
pid = pid2;
}
}
free(pids);
}
return retval;
}
static const struct {
const char * const name;
RC_SERVICE bit;
@@ -432,6 +423,7 @@ static const struct {
{ "service_hotplugged", RC_SERVICE_HOTPLUGGED, },
{ "service_wasinactive", RC_SERVICE_WASINACTIVE, },
{ "service_failed", RC_SERVICE_FAILED, },
{ "service_crashed", RC_SERVICE_CRASHED, },
};
RC_SERVICE lookup_service_state(const char *service)

56
src/rc/rc-pipes.c Normal file
View File

@@ -0,0 +1,56 @@
/*
* rc-pipes.c
* Helper to handle spawning processes and connecting them to pipes.
*/
/*
* Copyright (c) 2018 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.
*/
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include "rc-pipes.h"
static const int pipe_read_end = 0;
static const int pipe_write_end = 1;
/*
* Starts a command with stdin redirected from a pipe
* Returns the write end of the pipe or -1
*/
int rc_pipe_command(char *cmd)
{
int pfd[2];
pid_t pid;
if (pipe(pfd) < 0)
return -1;
pid = fork();
if (pid > 0) {
/* parent */
close(pfd[pipe_read_end]);
return pfd[pipe_write_end];
} else if (pid == 0) {
/* child */
close(pfd[pipe_write_end]);
if (pfd[pipe_read_end] != STDIN_FILENO) {
if (dup2(pfd[pipe_read_end], STDIN_FILENO) < 0)
exit(1);
close(pfd[pipe_read_end]);
}
execl("/bin/sh", "sh", "-c", cmd, NULL);
exit(1);
}
return -1;
}

18
src/rc/rc-pipes.h Normal file
View File

@@ -0,0 +1,18 @@
/*
* Copyright (c) 2018 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.
*/
#ifndef RC_PIPES_H
#define RC_PIPES_H
int rc_pipe_command(char *cmd);
#endif

View File

@@ -68,7 +68,7 @@ rc_plugin_load(void)
DIR *dp;
struct dirent *d;
PLUGIN *plugin;
char file[PATH_MAX];
char *file = NULL;
void *h;
int (*fptr)(RC_HOOK, const char *);
@@ -85,8 +85,9 @@ rc_plugin_load(void)
if (d->d_name[0] == '.')
continue;
snprintf(file, sizeof(file), RC_PLUGINDIR "/%s", d->d_name);
xasprintf(&file, RC_PLUGINDIR "/%s", d->d_name);
h = dlopen(file, RTLD_LAZY);
free(file);
if (h == NULL) {
eerror("dlopen: %s", dlerror());
continue;

View File

@@ -307,6 +307,9 @@ int run_stop_schedule(const char *applet,
const char *const *p;
bool progressed = false;
if (!(pid > 0 || exec || uid || (argv && *argv)))
return 0;
if (exec)
einfov("Will stop %s", exec);
if (pid > 0)
@@ -348,8 +351,9 @@ int run_stop_schedule(const char *applet,
tkilled += nkilled;
break;
case SC_FOREVER:
case SC_TIMEOUT:
if (item->value < 1) {
if (item->type == SC_TIMEOUT && item->value < 1) {
item = NULL;
break;
}
@@ -357,7 +361,7 @@ int run_stop_schedule(const char *applet,
ts.tv_sec = 0;
ts.tv_nsec = POLL_INTERVAL;
for (nsecs = 0; nsecs < item->value; nsecs++) {
for (nsecs = 0; item->type == SC_FOREVER || nsecs < item->value; nsecs++) {
for (nloops = 0;
nloops < ONE_SECOND / POLL_INTERVAL;
nloops++)
@@ -408,11 +412,12 @@ int run_stop_schedule(const char *applet,
if (progressed)
printf("\n");
if (! quiet)
if (! quiet) {
if (nrunning == 1)
eerror("%s: %d process refused to stop", applet, nrunning);
else
eerror("%s: %d process(es) refused to stop", applet, nrunning);
}
return -nrunning;
}

View File

@@ -256,19 +256,19 @@ static int read_context_file(const char *filename, char **context)
{
int ret = -1;
FILE *fp;
char filepath[PATH_MAX];
char *filepath = NULL;
char *line = NULL;
char *p;
char *p2;
size_t len = 0;
ssize_t read;
memset(filepath, '\0', PATH_MAX);
snprintf(filepath, PATH_MAX - 1, "%s/%s", selinux_contexts_path(), filename);
xasprintf(&filepath, "%s/%s", selinux_contexts_path(), filename);
fp = fopen(filepath, "r");
if (fp == NULL) {
eerror("Failed to open context file: %s", filename);
free(filepath);
return -1;
}
@@ -294,6 +294,7 @@ static int read_context_file(const char *filename, char **context)
}
free(line);
free(filepath);
fclose(fp);
return ret;
}

View File

@@ -29,23 +29,33 @@
const char *applet = NULL;
const char *extraopts = NULL;
const char *getoptstring = "e:ilr:IN" getoptstring_COMMON;
const char *getoptstring = "cdDe:ilr:INsSZ" getoptstring_COMMON;
const struct option longopts[] = {
{ "debug", 0, NULL, 'd' },
{ "nodeps", 0, NULL, 'D' },
{ "exists", 1, NULL, 'e' },
{ "ifcrashed", 0, NULL, 'c' },
{ "ifexists", 0, NULL, 'i' },
{ "ifinactive", 0, NULL, 'I' },
{ "ifnotstarted", 0, NULL, 'N' },
{ "ifstarted", 0, NULL, 's' },
{ "ifstopped", 0, NULL, 'S' },
{ "list", 0, NULL, 'l' },
{ "resolve", 1, NULL, 'r' },
{ "dry-run", 0, NULL, 'Z' },
longopts_COMMON
};
const char * const longopts_help[] = {
"set xtrace when running the command",
"ignore dependencies",
"tests if the service exists or not",
"if the service is crashed then run the command",
"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",
"dry run (show what would happen)",
longopts_help_COMMON
};
const char *usagestring = "" \
@@ -61,9 +71,12 @@ int main(int argc, char **argv)
RC_STRINGLIST *list;
RC_STRING *s;
RC_SERVICE state;
bool if_crashed = false;
bool if_exists = false;
bool if_inactive = false;
bool if_notstarted = false;
bool if_started = false;
bool if_stopped = false;
applet = basename_c(argv[0]);
/* Ensure that we are only quiet when explicitly told to be */
@@ -73,12 +86,21 @@ int main(int argc, char **argv)
longopts, (int *) 0)) != -1)
{
switch (opt) {
case 'd':
setenv("RC_DEBUG", "yes", 1);
break;
case 'D':
setenv("RC_NODEPS", "yes", 1);
break;
case 'e':
service = rc_service_resolve(optarg);
opt = service ? EXIT_SUCCESS : EXIT_FAILURE;
free(service);
return opt;
/* NOTREACHED */
case 'c':
if_crashed = true;
break;
case 'i':
if_exists = true;
break;
@@ -106,6 +128,15 @@ int main(int argc, char **argv)
free(service);
return EXIT_SUCCESS;
/* NOTREACHED */
case 's':
if_started = true;
break;
case 'S':
if_stopped = true;
break;
case 'Z':
setenv("IN_DRYRUN", "yes", 1);
break;
case_RC_COMMON_GETOPT
}
@@ -121,10 +152,16 @@ int main(int argc, char **argv)
eerrorx("%s: service `%s' does not exist", applet, *argv);
}
state = rc_service_state(*argv);
if (if_crashed && ! (rc_service_daemons_crashed(*argv) && errno != EACCES))
return 0;
if (if_inactive && ! (state & RC_SERVICE_INACTIVE))
return 0;
if (if_notstarted && (state & RC_SERVICE_STARTED))
return 0;
if (if_started && ! (state & RC_SERVICE_STARTED))
return 0;
if (if_stopped && ! (state & RC_SERVICE_STOPPED))
return 0;
*argv = service;
execv(*argv, argv);
eerrorx("%s: %s", applet, strerror(errno));

View File

@@ -54,7 +54,6 @@ const char *usagestring = "" \
"Usage: rc-status [options] <runlevel>...\n" \
" or: rc-status [options] [-a | -c | -l | -m | -r | -s | -u]";
static bool test_crashed = false;
static RC_DEPTREE *deptree;
static RC_STRINGLIST *types;
@@ -76,7 +75,7 @@ print_level(const char *prefix, const char *level)
printf("%s\n", level);
}
static void get_uptime(const char *service, char *uptime, int uptime_size)
static char *get_uptime(const char *service)
{
RC_SERVICE state = rc_service_state(service);
char *start_count;
@@ -88,8 +87,8 @@ static void get_uptime(const char *service, char *uptime, int uptime_size)
time_t diff_hours = (time_t) 0;
time_t diff_mins = (time_t) 0;
time_t diff_secs = (time_t) 0;
char *uptime = NULL;
uptime[0] = '\0';
if (state & RC_SERVICE_STARTED) {
start_count = rc_service_value_get(service, "start_count");
start_time_string = rc_service_value_get(service, "start_time");
@@ -111,58 +110,71 @@ static void get_uptime(const char *service, char *uptime, int uptime_size)
diff_secs %= diff_mins * (time_t) 60;
}
if (diff_days > 0)
snprintf(uptime, uptime_size,
xasprintf(&uptime,
"%ld day(s) %02ld:%02ld:%02ld (%s)",
diff_days, diff_hours, diff_mins, diff_secs,
start_count);
else
snprintf(uptime, uptime_size,
xasprintf(&uptime,
"%02ld:%02ld:%02ld (%s)",
diff_hours, diff_mins, diff_secs, start_count);
}
}
return uptime;
}
static void
print_service(const char *service)
{
char status[60];
char uptime [40];
char *status = NULL;
char *uptime = NULL;
char *child_pid = NULL;
char *start_time = NULL;
int cols = printf(" %s", service);
const char *c = ecolor(ECOLOR_GOOD);
RC_SERVICE state = rc_service_state(service);
ECOLOR color = ECOLOR_BAD;
if (state & RC_SERVICE_STOPPING)
snprintf(status, sizeof(status), "stopping ");
xasprintf(&status, "stopping ");
else if (state & RC_SERVICE_STARTING) {
snprintf(status, sizeof(status), "starting ");
xasprintf(&status, "starting ");
color = ECOLOR_WARN;
} else if (state & RC_SERVICE_INACTIVE) {
snprintf(status, sizeof(status), "inactive ");
xasprintf(&status, "inactive ");
color = ECOLOR_WARN;
} else if (state & RC_SERVICE_STARTED) {
errno = 0;
if (test_crashed &&
rc_service_daemons_crashed(service) &&
errno != EACCES)
if (rc_service_daemons_crashed(service) && errno != EACCES)
{
snprintf(status, sizeof(status), " crashed ");
child_pid = rc_service_value_get(service, "child_pid");
start_time = rc_service_value_get(service, "start_time");
if (start_time && child_pid)
xasprintf(&status, " unsupervised ");
else
xasprintf(&status, " crashed ");
free(child_pid);
free(start_time);
} else {
get_uptime(service, uptime, 40);
snprintf(status, sizeof(status), " started %s", uptime);
uptime = get_uptime(service);
if (uptime) {
xasprintf(&status, " started %s", uptime);
free(uptime);
} else
xasprintf(&status, " started ");
color = ECOLOR_GOOD;
}
} else if (state & RC_SERVICE_SCHEDULED) {
snprintf(status, sizeof(status), "scheduled");
xasprintf(&status, "scheduled");
color = ECOLOR_WARN;
} else
snprintf(status, sizeof(status), " stopped ");
xasprintf(&status, " stopped ");
errno = 0;
if (c && *c && isatty(fileno(stdout)))
printf("\n");
ebracket(cols, color, status);
free(status);
}
static void
@@ -231,8 +243,6 @@ int main(int argc, char **argv)
char *p, *runlevel = NULL;
int opt, retval = 0;
test_crashed = _rc_can_find_pids();
applet = basename_c(argv[0]);
while ((opt = getopt_long(argc, argv, getoptstring, longopts,
(int *) 0)) != -1)

View File

@@ -62,7 +62,7 @@ add(const char *runlevel, const char *service)
if (!rc_service_exists(service)) {
if (errno == ENOEXEC)
eerror("%s: service `%s' is not executeable",
eerror("%s: service `%s' is not executable",
applet, service);
else
eerror("%s: service `%s' does not exist",
@@ -166,7 +166,7 @@ show(RC_STRINGLIST *runlevels, bool verbose)
RC_STRING *runlevel;
RC_STRINGLIST *in;
bool inone;
char buffer[PATH_MAX];
char *buffer = NULL;
size_t l;
rc_stringlist_sort(&services);
@@ -182,9 +182,11 @@ show(RC_STRINGLIST *runlevels, bool verbose)
inone = true;
} else {
l = strlen(runlevel->value);
buffer = xmalloc(l+1);
memset (buffer, ' ', l);
buffer[l] = 0;
rc_stringlist_add (in, buffer);
free(buffer);
}
}

View File

@@ -42,7 +42,7 @@ void log_wtmp(const char *user, const char *id, pid_t pid, int type,
strncpy(utmp.ut_name, user, sizeof(utmp.ut_name));
strncpy(utmp.ut_id , id , sizeof(utmp.ut_id ));
strncpy(utmp.ut_line, line, sizeof(utmp.ut_line));
/* Put the OS version in place of the hostname */
if (uname(&uname_buf) == 0)
strncpy(utmp.ut_host, uname_buf.release, sizeof(utmp.ut_host));

Some files were not shown because too many files have changed in this diff Show More