mirror of
https://github.com/troglobit/finit.git
synced 2026-10-12 10:12:32 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
83915b42f3 | ||
|
|
babcd117b1 | ||
|
|
892ac2edb2 | ||
|
|
5b12d17b56 | ||
|
|
1b6930126e | ||
|
|
8def97a465 | ||
|
|
7bbc0847b1 | ||
|
|
88dc3f0061 | ||
|
|
02e69932ae | ||
|
|
662dfbe777 | ||
|
|
c249cbdbe1 | ||
|
|
a47171891f | ||
|
|
1dc67acd40 | ||
|
|
146685c2c2 | ||
|
|
3cc2df20f9 | ||
|
|
4f3d246100 | ||
|
|
11bfec1a23 | ||
|
|
f24a03a32c | ||
|
|
829ff0b9f7 | ||
|
|
b9ae4d04ef | ||
|
|
47060c9738 | ||
|
|
846692ca03 | ||
|
|
985d53bec4 | ||
|
|
8548e67dcd | ||
|
|
1c60e949e7 | ||
|
|
86f02e8553 | ||
|
|
2c7332583c | ||
|
|
a96b74ea5e | ||
|
|
5a1b13ff41 | ||
|
|
4a71f19c40 | ||
|
|
5c672885f1 | ||
|
|
e38eb7cbd5 | ||
|
|
ba9ae0337d | ||
|
|
b674aad802 | ||
|
|
88f9458c6e | ||
|
|
6cb3d86cd1 | ||
|
|
5cde809909 | ||
|
|
1b6931eaea | ||
|
|
c3b7530b98 | ||
|
|
0f61b0792b | ||
|
|
bab13c9cef | ||
|
|
9c9fe51eee | ||
|
|
4f8211f6a1 | ||
|
|
5fc3a0a3b9 | ||
|
|
67c55145b9 | ||
|
|
fc2489d9e1 | ||
|
|
a384a95529 | ||
|
|
a013e48ab5 | ||
|
|
24a0ddfc59 | ||
|
|
3da4c2abe9 | ||
|
|
2950820d34 | ||
|
|
75b1ac8199 | ||
|
|
8f05b36551 | ||
|
|
0f840e6576 | ||
|
|
451f63ebe0 | ||
|
|
2dc9daf118 | ||
|
|
3c67a10347 | ||
|
|
6885a9f868 | ||
|
|
38142baa93 | ||
|
|
34bdbdb3b1 | ||
|
|
83af7e8e9d | ||
|
|
4eb5f8a0dc | ||
|
|
e03b358ff0 | ||
|
|
d2846b805a | ||
|
|
07d767e1af | ||
|
|
d423e6b774 | ||
|
|
bb89bdd8a9 | ||
|
|
5cc98f6e53 | ||
|
|
a6300f6ac6 | ||
|
|
aeabb4d2ea | ||
|
|
dcbb429863 | ||
|
|
077d52d209 | ||
|
|
44f5de188d | ||
|
|
191e5440b2 | ||
|
|
a2b0d00058 | ||
|
|
e8fa827026 | ||
|
|
89105090ed | ||
|
|
6ce218612b | ||
|
|
dd87c81adc | ||
|
|
37f3478873 | ||
|
|
a64259362e | ||
|
|
3554138118 | ||
|
|
f7d6d269c7 | ||
|
|
2c1e9877f9 | ||
|
|
a94c97221e | ||
|
|
f9732a6fb9 | ||
|
|
581fc956be | ||
|
|
ee901b018c | ||
|
|
d373ebfdd7 | ||
|
|
698b87dd35 |
+3
-3
@@ -33,11 +33,11 @@ addons:
|
||||
branch_pattern: dev
|
||||
|
||||
install:
|
||||
- wget https://github.com/troglobit/libuev/releases/download/v1.4.2/libuev-1.4.2.tar.xz
|
||||
- wget https://github.com/troglobit/libuev/releases/download/v1.5.2/libuev-1.5.2.tar.xz
|
||||
- wget https://github.com/troglobit/libite/releases/download/v1.8.2/libite-1.8.2.tar.xz
|
||||
- tar xf libuev-1.4.2.tar.xz
|
||||
- tar xf libuev-1.5.2.tar.xz
|
||||
- tar xf libite-1.8.2.tar.xz
|
||||
- (cd libuev-1.4.2 && ./configure --prefix=/tmp && make && make install-strip)
|
||||
- (cd libuev-1.5.2 && ./configure --prefix=/tmp && make && make install-strip)
|
||||
- (cd libite-1.8.2 && ./configure --prefix=/tmp && make && make install-strip)
|
||||
|
||||
# Custom build script for the time being, no "make test" yet
|
||||
|
||||
+8
-4
@@ -14,11 +14,15 @@ finit_SOURCES = api.c \
|
||||
sm.c sm.h \
|
||||
svc.c svc.h \
|
||||
tty.c tty.h \
|
||||
util.c util.h \
|
||||
utmp-api.c utmp-api.h
|
||||
pkginclude_HEADERS = cond.h finit.h helpers.h inetd.h plugin.h svc.h
|
||||
if INETD
|
||||
finit_SOURCES += inetd.c inetd.h
|
||||
endif
|
||||
if WATCHDOGD
|
||||
finit_SOURCES += watchdog.c watchdog.h
|
||||
endif
|
||||
|
||||
finit_CFLAGS = -W -Wall -Wextra -std=gnu99 $(lite_CFLAGS) $(uev_CFLAGS)
|
||||
finit_LDADD = $(lite_LIBS) $(uev_LIBS)
|
||||
@@ -29,14 +33,14 @@ finit_LDADD += -ldl
|
||||
endif
|
||||
|
||||
initctl_SOURCES = initctl.c svc.c svc.h helpers.c helpers.h cond.c cond.h \
|
||||
utmp-api.c utmp-api.h
|
||||
util.c util.h utmp-api.c utmp-api.h
|
||||
initctl_CFLAGS = $(lite_CFLAGS)
|
||||
initctl_LDADD = $(lite_LIBS)
|
||||
|
||||
reboot_SOURCES = reboot.c
|
||||
reboot_SOURCES = reboot.c util.c util.h
|
||||
|
||||
INIT_LNKS = telinit init
|
||||
REBOOT_LNKS = shutdown halt suspend
|
||||
REBOOT_LNKS = shutdown halt poweroff suspend
|
||||
SUBDIRS = plugins
|
||||
doc_DATA = README.md LICENSE finit.conf
|
||||
EXTRA_DIST = README.md LICENSE ChangeLog.md finit.conf
|
||||
@@ -65,7 +69,7 @@ install-exec-hook:
|
||||
fi; \
|
||||
done
|
||||
@if [ -L $(DESTDIR)$(sbindir)/reboot ]; then \
|
||||
echo "Non-finit reboot, skipping."; \
|
||||
echo "Non-finit reboot, skipping install."; \
|
||||
else \
|
||||
for file in $(REBOOT_LNKS); do \
|
||||
link=$(DESTDIR)$(sbindir)/$$file; \
|
||||
|
||||
@@ -1,19 +1,8 @@
|
||||
```
|
||||
_______ __ _____ ___ __ ___________ _______
|
||||
/" "||" \ (\" \|" \ |" \(" _ ")/" __ )
|
||||
(: ______)|| | |.\\ \ | || |)__/ \\__/(__/ _) ./
|
||||
\/ | |: | |: \. \\ | |: | \\_ / / //
|
||||
// ___) |. | |. \ \. | |. | |. | __ \_ \\
|
||||
(: ( /\ |\| \ \ | /\ |\ \: | (: \__) :\
|
||||
\__/ (__\_|_)\___|\____\)(__\_|_) \__| \_______) ... Yes, we need a new logo!
|
||||
```
|
||||
|
||||
Fast init for Linux
|
||||
===================
|
||||
[![Travis Status]][Travis] [![Coverity Status]][Coverity Scan]
|
||||
<p align="center"><img src="images/finit3.png" alt="Finit: Fast Init" /></p>
|
||||
|
||||
Table of Contents
|
||||
-----------------
|
||||
[![Travis Status]][Travis] [![Coverity Status]][Coverity Scan]
|
||||
|
||||
* [Introduction](#introduction)
|
||||
* [Features](#features)
|
||||
@@ -27,6 +16,7 @@ Table of Contents
|
||||
* [Rebooting & Halting](#rebooting--halting)
|
||||
* [Commands & Status](#commands--status)
|
||||
* [Building](doc/build.md#building)
|
||||
* [Requirements](#requirements)
|
||||
* [Running](#running)
|
||||
* [Debugging](#debugging)
|
||||
* [Origin & References](#origin--references)
|
||||
@@ -35,11 +25,15 @@ Table of Contents
|
||||
Introduction
|
||||
------------
|
||||
|
||||
Finit is an EeePC inspired Fastinit clone with [process supervision][1]
|
||||
Finit is an EeePC Fastinit inspired clone with [process supervision][1]
|
||||
similar to that of D.J. Bernstein's [daemontools][2] and Gerrit Pape's
|
||||
[runit][3]. The focus of Finit is on small and embedded Linux systems,
|
||||
although it is fully usable on server and desktop installations as well.
|
||||
See the [contrib section](contrib/) for Debian and Alpine examples.
|
||||
[runit][3]. It also supports free-form conditions based on events, e.g.
|
||||
triggering on PID file creation, Netlink events like a default route or
|
||||
interfaces coming up, or even custom events. Similar to [systemd][6].
|
||||
|
||||
Finit focuses on small and embedded Linux systems, although fully usable
|
||||
on servers and desktops as well. See the [contrib section](contrib/)
|
||||
for Debian and Alpine Linux examples.
|
||||
|
||||
Traditional [SysV init][4] style systems are scripted. For low-resource
|
||||
embedded systems this is quite resource intensive and often leads to
|
||||
@@ -140,26 +134,26 @@ nasty bits with PAM etc.
|
||||
|
||||
**Runlevels**
|
||||
|
||||
Runlevels are optional in Finit, but support for [SysV runlevels][5] is
|
||||
available if needed. All services in runlevel S(1) are started first,
|
||||
followed by the desired run-time runlevel. Runlevel S can be started in
|
||||
sequence by using `run [S] cmd`. Changing runlevels at runtime is done
|
||||
like any other init, e.g. <kbd>init 4</kbd>
|
||||
Support for SysV init-style [runlevels][5] is available, in the same
|
||||
minimal style as everything else in Finit. The `[2345]` syntax can be
|
||||
applied to service, task, run, inetd, and TTY stanzas.
|
||||
|
||||
All services in runlevel S(1) are started first, followed by the desired
|
||||
run-time runlevel. Runlevel S can be started in sequence by using `run
|
||||
[S] cmd`. Changing runlevels at runtime is done like any other init,
|
||||
e.g. <kbd>init 4</kbd>, but also using the more advanced `intictl` tool.
|
||||
|
||||
|
||||
**Plugins**
|
||||
|
||||
Finit plugins can be *callbacks*, *boot hooks* into different stages of
|
||||
the boot process, or *pure extensions*. Plugins are written in C and
|
||||
compiled into a dynamic library that is loaded automatically by finit at
|
||||
boot. A basic set of plugins that extend and modify the basic behavior
|
||||
are bundled in the `plugins/` directory.
|
||||
Plugins can *extend* the functionality of Finit and *hook into* the
|
||||
different stages of the boot process and at runtime. Plugins are
|
||||
written in C and compiled into a dynamic library loaded automatically by
|
||||
finit at boot. A basic set of plugins are bundled in the `plugins/`
|
||||
directory.
|
||||
|
||||
Capabilities:
|
||||
|
||||
- **Task/Run/Service callbacks**
|
||||
Modify service arguments, override service monitor's decisions to
|
||||
start/stop/reload a service.
|
||||
- **Hooks**
|
||||
Hook into the boot at predefined points to extend Finit
|
||||
- **I/O**
|
||||
@@ -178,7 +172,7 @@ For more information, see [doc/plugins.md](doc/plugins.md).
|
||||
Runparts & /etc/rc.local
|
||||
------------------------
|
||||
|
||||
At the end of the boot, when networking and all services are up, finit
|
||||
At the end of the boot, when networking and all services are up, Finit
|
||||
calls its built-in [run-parts(8)][] on the `runparts <DIR>` directory,
|
||||
and `/etc/rc.local`, in that order if they exist.
|
||||
|
||||
@@ -210,7 +204,7 @@ are used, and even more commonly, only the default runlevel is used.
|
||||
To specify an allowed set of runlevels for a `service`, `run` command,
|
||||
`task`, or `tty`, add `[NNN]` to your `/etc/finit.conf`, like this:
|
||||
|
||||
```shell
|
||||
```
|
||||
service [S12345] /sbin/syslogd -n -x -- System log daemon
|
||||
run [S] /etc/init.d/acpid start -- Starting ACPI Daemon
|
||||
task [S] /etc/init.d/kbd start -- Preparing console
|
||||
@@ -247,58 +241,36 @@ start any new ones for you, without rebooting the system.
|
||||
Rebooting & Halting
|
||||
-------------------
|
||||
|
||||
Finit is often used on embedded and small Linux systems with BusyBox.
|
||||
For compatibility with its existing toolset (halt, poweroff, reboot),
|
||||
the following signals have been adopted:
|
||||
Traditionally, rebooting and halting a UNIX system is done by changing
|
||||
its runlevel. Finit comes with its own tooling providing: `shutdown`,
|
||||
`reboot`, `poweroff`, and `suspend`, but also the traditional `init` and
|
||||
`telinit`, as well as a more modern `initctl` tool, detailed in the next
|
||||
section.
|
||||
|
||||
* `SIGUSR1`
|
||||
Same effect as `finit q`, reloads all *.conf files in `/etc/finit.d/`
|
||||
* `SIGUSR1`
|
||||
Calls shutdown hooks, including HOOK_SHUTDOWN, stops all running
|
||||
processes, and unmounts all file systems. Then tells kernel to
|
||||
halt. Most people these days want SIGUSR2 though.
|
||||
For compatibility reasons Finit listens to the same set of signals as
|
||||
BusyBox init. This is not 100% compatible with SysV init, but clearly
|
||||
the more common combination for Finit. For more details, see
|
||||
[doc/signals.md](doc/signals.md).
|
||||
|
||||
SysV init and systemd use this to re-open their FIFO/D-Bus.
|
||||
* `SIGUSR2`
|
||||
Like SIGUSR1, but tell kernel to power-off the system, if ACPI
|
||||
or similar exists to actually do this. If the kernel fails
|
||||
power-off, Finit falls back to halt.
|
||||
|
||||
SysV init N/A, systemd dumps its internal state to log.
|
||||
* `SIGTERM`
|
||||
Like `SIGUSR1`, but tell kernel to reboot the system when done.
|
||||
|
||||
SysV init N/A, systemd rexecutes itself.
|
||||
* `SIGINT`
|
||||
Sent from kernel when the CTRL-ALT-DEL key combo is pressed.
|
||||
SysV init and systemd default to reboot with `shutdown -r`.
|
||||
Finit currently forwards this to `SIGTERM`.
|
||||
* `SIGPWR`
|
||||
Sent from a power daemon, like `powstatd(8)`, on changes to the
|
||||
UPS status. Traditionally SysV init read /etc/powerstatus and
|
||||
acted on "OK", "FAIL", or "LOW" and then removed the file.
|
||||
Finit currently forwards this to `SIGUSR2`.
|
||||
Finit also listens to the classic SysV init FIFO, used by `telinit`.
|
||||
Support for this is implemented by the `initctl.so` plugin. Hence,
|
||||
`telinit q` will work as the UNIX beards intended.
|
||||
|
||||
Finit also listens to the classic SysV init FIFO, which used to be
|
||||
located in `/dev` but these days default to `/run/initctl`. So existing
|
||||
tools like, `poweroff`, `halt`, `reboot`, and `shutdown` work as
|
||||
expected. Support for this old-style handling is implemented in the
|
||||
optional `initctl.so` plugin and can be accessed with the traditional
|
||||
`telinit` command line tool, symlinked to `finit`. Hence, if finit is
|
||||
your system init, then `init q` will work as the UNIX beards intended.
|
||||
|
||||
```shell
|
||||
~ $ telinit
|
||||
~ # telinit -h
|
||||
Usage: telinit [OPTIONS] [q | Q | 0-9]
|
||||
|
||||
Options:
|
||||
-h, --help This help text
|
||||
-v, --version Show Finit version
|
||||
-h, --help This help text
|
||||
-V, --version Show Finit version
|
||||
|
||||
Commands:
|
||||
q | Q Reload *.conf in /etc/finit.d/, like SIGHUP
|
||||
0 - 9 Change runlevel: 0 halt, 6 reboot
|
||||
```
|
||||
0 Power-off the system, same as initctl poweroff
|
||||
6 Reboot the system, same as initctl reboot
|
||||
2, 3, 4, 5 Change runlevel. Starts services in new runlevel, stops any
|
||||
services in prev. runlevel that are not allowed in new.
|
||||
q, Q Reload *.conf in /etc/finit.d/, same as initctl reload or
|
||||
sending SIGHUP to PID 1
|
||||
1, s, S Enter system rescue mode, runlevel 1
|
||||
|
||||
|
||||
Commands & Status
|
||||
@@ -308,7 +280,6 @@ Finit also implements a more modern API to query status, and start/stop
|
||||
services, called `initctl`. Unlike `telinit` the `initctl` tool does
|
||||
not return until the given command has fully completed.
|
||||
|
||||
```shell
|
||||
~ $ initctl -h
|
||||
Usage: initctl [OPTIONS] <COMMAND>
|
||||
|
||||
@@ -332,21 +303,17 @@ not return until the given command has fully completed.
|
||||
restart <JOB|NAME>[:ID] Restart (stop/start) service by job# or name
|
||||
reload <JOB|NAME>[:ID] Reload (SIGHUP) service by job# or name
|
||||
version Show Finit version
|
||||
```
|
||||
|
||||
The `<!>` notation to a service stanza can be used empty, then it will
|
||||
apply to `reload` and `runlevel` commands. I.e., when a service's
|
||||
`.conf` file has been changed Finit will stop and start it instead. If
|
||||
a service does *not* have `<!>` declared, the service will be reloaded
|
||||
(`SIGHUP`:ed) in the `START` phase instead. The latter is the preferred
|
||||
behaviour, but not all daemons support this, unfortunately.
|
||||
For services *not* supporting `SIGHUP` the `<!>` notation in the .conf
|
||||
file must be used to tell Finit to stop and start it on `reload` and
|
||||
`runlevel` changes. If `<>` holds more [conditions](doc/conditions.md),
|
||||
these will also affect how a service is maintained.
|
||||
|
||||
**Note:** even though it is possible to start services not belonging to
|
||||
**Note:** even though it is possible to start services not belonging in
|
||||
the current runlevel these services will not be respawned automatically
|
||||
by Finit if they exit (crash). Hence, if the runlevel is 2, the below
|
||||
Dropbear SSH service will not be restarted if it is killed or exits.
|
||||
|
||||
```shell
|
||||
~ $ initctl status -v
|
||||
1 running 476 [S12345] /sbin/watchdog -T 16 -t 2 -F /dev/watchdog
|
||||
2 running 477 [S12345] /sbin/syslogd -n -b 3 -D
|
||||
@@ -358,7 +325,33 @@ Dropbear SSH service will not be restarted if it is killed or exits.
|
||||
5:2 inetd 0 [2345] /sbin/telnetd allow eth0:2323,eth2:2323,eth1:2323
|
||||
6:1 inetd 0 [345] /sbin/dropbear allow eth0:222
|
||||
6:2 inetd 0 [345] /sbin/dropbear allow *:22 deny eth0
|
||||
```
|
||||
|
||||
|
||||
Requirements
|
||||
------------
|
||||
|
||||
Finit is capable of running on both desktop/server systems with udev and
|
||||
embedded systems that usually come with BusyBox mdev. Finit probes for
|
||||
them at runtime and expects `/dev/` to be writable, usually `devtmpfs`.
|
||||
It is also possible to run on a statically set up `/dev` if needed. It
|
||||
is however not a good idea to have both udev and mdev installed at the
|
||||
same time, this will lead to unpredictable results.
|
||||
|
||||
At boot Finit calls either `mdev` or `udevd` to populate `/dev`, this is
|
||||
done slightly differently and on systems with udev you might want to add
|
||||
the following one-shot task early in your `/etc/finit.conf`:
|
||||
|
||||
run [S] /sbin/udevadm settle --timeout=120 -- Waiting for udev
|
||||
|
||||
Finit has a built-in Getty for TTYs, but requires a working `/bin/login`
|
||||
or `/bin/sh`, if no TTYs are configured in `/etc/finit.conf`.
|
||||
|
||||
For a fully operational system `/var`, `/run` and `/tmp` must be set up
|
||||
properly in `/etc/fstab` -- which is iterated over at boot.
|
||||
|
||||
The built-in Inetd requires `/etc/services` and `/etc/protocols` to work
|
||||
with port names rather than numbers.
|
||||
|
||||
|
||||
Running
|
||||
-------
|
||||
@@ -373,25 +366,29 @@ LILO, U-Boot/Barebox or RedBoot) configuration to append the following
|
||||
to the kernel command line:
|
||||
|
||||
```shell
|
||||
init=/sbin/finit
|
||||
append="init=/sbin/finit"
|
||||
```
|
||||
|
||||
Remember to also set up an initial `/etc/finit.conf` before rebooting!
|
||||
|
||||

|
||||

|
||||
|
||||
|
||||
Debugging
|
||||
---------
|
||||
|
||||
Add `finit_debug`, or `--debug`, to the kernel command line to enable
|
||||
debug messages. See the output from `configure --help` for more on
|
||||
how to assist debugging.
|
||||
debug messages.
|
||||
|
||||
```shell
|
||||
init=/sbin/finit --debug
|
||||
append="init=/sbin/finit --debug"
|
||||
```
|
||||
|
||||
To debug startup issues, in particular issues with getty/login, try
|
||||
`configure --enable-fallback-shell`. When no TTYs are detected, and
|
||||
Finit is configured with this option, Finit will try to start a bare
|
||||
`/bin/sh` on the boot console.
|
||||
|
||||
|
||||
Origin & References
|
||||
-------------------
|
||||
@@ -410,6 +407,7 @@ and proposed extensions.
|
||||
[3]: http://smarden.org/runit/
|
||||
[4]: http://en.wikipedia.org/wiki/Init
|
||||
[5]: http://en.wikipedia.org/wiki/Runlevel
|
||||
[6]: https://www.freedesktop.org/wiki/Software/systemd/
|
||||
[9]: https://github.com/troglobit/troglos
|
||||
[run-parts(8)]: http://manpages.debian.org/cgi-bin/man.cgi?query=run-parts
|
||||
[original finit]: http://helllabs.org/finit/
|
||||
|
||||
@@ -20,8 +20,6 @@ General
|
||||
|
||||
* Add halt/poweroff/shutdown symlinks to finit and convert reboot, but
|
||||
only install symlinks if these tools don't already exist.
|
||||
* Step state machine at shutdown instead of killing, same as shifting to
|
||||
runlevel 0 or 6, then call external (newly installed?) tool to reboot.
|
||||
* Add support for timed shutdown in Finit, including cancelled shutdown.
|
||||
* SysV init and systemd use SIGUSR1 to restart their FIFO/D-Bus. Add
|
||||
API restart to SIGHUP callback for the same functionality in Finit.
|
||||
@@ -40,6 +38,8 @@ General
|
||||
`service <SVC> stop|start|restart|reload|status` on top
|
||||
* Add support for JSON output, or similar, from `initctl show`, e.g.
|
||||
`initctl show --json`
|
||||
* Improve output of `initctl show SVC`, list service uptime, last
|
||||
ten relevant logs, etc. Similar to `systemctl show SVC`
|
||||
* Add PRE and POST hooks for when switching between runlevels
|
||||
|
||||
|
||||
@@ -55,11 +55,14 @@ to achieve compatibility would be to add a plugin to finit which reads
|
||||
Inetd
|
||||
-----
|
||||
|
||||
Add support for throttling connections.
|
||||
|
||||
Optimize interface filtering by using socket filter. The functions
|
||||
`inet_*_peek()` and `inetd_is_allowed()` used for interace filtering
|
||||
should be possible to rewrite as socket filters.
|
||||
* Add support for throttling connections.
|
||||
* Optimize interface filtering by using socket filter. The functions
|
||||
`inet_*_peek()` and `inetd_is_allowed()` used for interace filtering
|
||||
should be possible to rewrite as socket filters.
|
||||
* Optimize HTTP/HTTPS inetd connections by adding basic support for the
|
||||
`inetd` variant `redir http/tcp@eth0 nowait [2345] 127.0.0.1:8080`,
|
||||
which would reduce the overhead of spawn the web server on each HTTP
|
||||
connection, yet still provide a means of filtering access per iface.
|
||||
|
||||
|
||||
Crond
|
||||
@@ -93,44 +96,6 @@ the shell -- that way setting up one-time jobs would not entail
|
||||
re-reading `/etc/finit.conf`
|
||||
|
||||
|
||||
Watchdog
|
||||
--------
|
||||
|
||||
Support for monitoring the health of the system and its processes.
|
||||
|
||||
* Add support for a `/dev/watchdog` built-in to replace both the BusyBox
|
||||
watchdogd and my own refreshed uClinux-dist adaptation,
|
||||
[watchdogd](https://github.com/troglobit/watchdogd)
|
||||
* Add a system supervisor (pmon) to optionally reboot the system when a
|
||||
process stops responding, or when a respawn limit has been reached, as
|
||||
well as when system load gets too high. For details on UNIX loadavg,
|
||||
see http://stackoverflow.com/questions/11987495/linux-proc-loadavg
|
||||
- Default to 0.7 as MAX recommended load before warning and 0.9 reboot
|
||||
* API for processes to register with the watchdog, libwdt
|
||||
- Deeper monitoring of a process' main loop by instrumenting
|
||||
- If a process is not heard from within its subscribed period time
|
||||
reboot system or restart process.
|
||||
- Add client libwdt library, inspired by old Westermo API and the
|
||||
[libwdt][] API published in the [Fritz!Box source dump][], take for
|
||||
instance the `fritzbox7170-source-files-04.87-tar.gz` drop and see
|
||||
the `GPL-release_kernel.tgz` in `drivers/char/avm_new/` for the
|
||||
kernel driver, and the `LGPL-GPL-release_target_tools.tgz` in `wdt/`
|
||||
for the userland API.
|
||||
- When a client process (a standard app/daemon instrumented with
|
||||
libwdt calls in its main loop) registers with the watchdog, we raise
|
||||
the RT priority to 98 (just below the kernel watchdog in prio).
|
||||
This to ensure that system monitoring goes before anything else in
|
||||
the system.
|
||||
- Use UNIX domain sockets for communication between daemon and clients
|
||||
* Separate `/etc/watchdog.conf` configuration file, or a perhaps
|
||||
support for a more generic `/etc/finit.d/PLUGIN.conf`?
|
||||
* Support enable/disable watchdog features:
|
||||
- Supervise processes,
|
||||
- CPU loadavg,
|
||||
- Watch for file descriptor leaks,
|
||||
- etc.
|
||||
|
||||
|
||||
Documentation
|
||||
-------------
|
||||
|
||||
|
||||
@@ -217,9 +217,14 @@ static int do_handle_emit(char *buf, size_t len)
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* In contrast to the SysV compat handling in plugins/initctl.c, when
|
||||
* `initctl runlevel 0` is issued we default to POWERDOWN the system
|
||||
* instead of just halting.
|
||||
*/
|
||||
static void cb(uev_t *w, void *UNUSED(arg), int UNUSED(events))
|
||||
{
|
||||
int sd;
|
||||
int sd, lvl;
|
||||
struct init_request rq;
|
||||
|
||||
sd = accept(w->fd, NULL, NULL);
|
||||
@@ -255,26 +260,19 @@ static void cb(uev_t *w, void *UNUSED(arg), int UNUSED(events))
|
||||
switch (rq.cmd) {
|
||||
case INIT_CMD_RUNLVL:
|
||||
switch (rq.runlevel) {
|
||||
case '0':
|
||||
_d("Halting system (SIGUSR2)");
|
||||
do_shutdown(SHUT_OFF);
|
||||
break;
|
||||
|
||||
case 's':
|
||||
case 'S':
|
||||
_d("Cannot enter bootstrap after boot ...");
|
||||
rq.runlevel = '1';
|
||||
rq.runlevel = '1'; /* Single user mode */
|
||||
/* Fall through to regular processing */
|
||||
|
||||
case '1'...'5':
|
||||
case '7'...'9':
|
||||
case '0'...'9':
|
||||
_d("Setting new runlevel %c", rq.runlevel);
|
||||
service_runlevel(rq.runlevel - '0');
|
||||
break;
|
||||
|
||||
case '6':
|
||||
_d("Rebooting system (SIGUSR1)");
|
||||
do_shutdown(SHUT_REBOOT);
|
||||
lvl = rq.runlevel - '0';
|
||||
if (lvl == 0)
|
||||
halt = SHUT_OFF;
|
||||
if (lvl == 6)
|
||||
halt = SHUT_REBOOT;
|
||||
service_runlevel(lvl);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -319,13 +317,25 @@ static void cb(uev_t *w, void *UNUSED(arg), int UNUSED(events))
|
||||
|
||||
case INIT_CMD_GET_RUNLEVEL:
|
||||
rq.runlevel = runlevel;
|
||||
result = 0;
|
||||
break;
|
||||
|
||||
case INIT_CMD_ACK:
|
||||
_d("Client failed reading ACK");
|
||||
goto leave;
|
||||
|
||||
case INIT_CMD_WDOG_HELLO:
|
||||
if (rq.runlevel <= 0) {
|
||||
result = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (wdogpid > 0 && wdogpid != rq.runlevel) {
|
||||
kill(wdogpid, SIGTERM);
|
||||
do_sleep(1);
|
||||
}
|
||||
wdogpid = rq.runlevel;
|
||||
break;
|
||||
|
||||
default:
|
||||
_d("Unsupported cmd: %d", rq.cmd);
|
||||
break;
|
||||
@@ -347,6 +357,7 @@ leave:
|
||||
int api_init(uev_ctx_t *ctx)
|
||||
{
|
||||
int sd;
|
||||
mode_t oldmask;
|
||||
struct sockaddr_un sun = {
|
||||
.sun_family = AF_UNIX,
|
||||
.sun_path = INIT_SOCKET,
|
||||
@@ -359,17 +370,20 @@ int api_init(uev_ctx_t *ctx)
|
||||
}
|
||||
|
||||
erase(INIT_SOCKET);
|
||||
oldmask = umask(0077);
|
||||
if (-1 == bind(sd, (struct sockaddr*)&sun, sizeof(sun)))
|
||||
goto error;
|
||||
|
||||
if (-1 == listen(sd, 10))
|
||||
goto error;
|
||||
|
||||
umask(oldmask);
|
||||
if (!uev_io_init(ctx, &api_watcher, cb, NULL, sd, UEV_READ))
|
||||
return 0;
|
||||
|
||||
error:
|
||||
_pe("Failed intializing API socket");
|
||||
umask(oldmask);
|
||||
close(sd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include <lite/lite.h>
|
||||
|
||||
#include "finit.h"
|
||||
#include "util.h"
|
||||
|
||||
static int do_send(struct init_request *rq)
|
||||
{
|
||||
@@ -39,7 +40,7 @@ static int do_send(struct init_request *rq)
|
||||
|
||||
if (fd == -1) {
|
||||
if (!fexist(FINIT_FIFO)) {
|
||||
fprintf(stderr, "%s does not support %s!\n", __progname, FINIT_FIFO);
|
||||
fprintf(stderr, "%s does not support %s!\n", prognm, FINIT_FIFO);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -108,7 +109,7 @@ static int usage(int rc)
|
||||
" q, Q Reload *.conf in /etc/finit.d/, same as initctl reload or\n"
|
||||
" sending SIGHUP to PID 1\n"
|
||||
" 1, s, S Enter system rescue mode, runlevel 1\n"
|
||||
"\n", __progname);
|
||||
"\n", prognm);
|
||||
|
||||
return rc;
|
||||
}
|
||||
@@ -123,6 +124,7 @@ int client(int argc, char *argv[])
|
||||
};
|
||||
|
||||
silent = 1;
|
||||
progname(argv[0]);
|
||||
while ((c = getopt_long(argc, argv, "h?v", long_options, NULL)) != EOF) {
|
||||
switch(c) {
|
||||
case 'v':
|
||||
|
||||
@@ -89,14 +89,11 @@ static void cond_update(const char *name)
|
||||
svc_t *svc;
|
||||
|
||||
_d("%s", name);
|
||||
if (!name)
|
||||
return;
|
||||
|
||||
for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) {
|
||||
if (!svc_has_cond(svc) || !cond_affects(name, svc->cond))
|
||||
continue;
|
||||
|
||||
_d("%s: match <%s> %s", name, svc->cond, svc->cmd);
|
||||
_d("%s: match <%s> %s", name ?: "nil", svc->cond, svc->cmd);
|
||||
service_step(svc);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -197,7 +197,7 @@ void conf_parse_rlimit(char *line)
|
||||
} else {
|
||||
const char *err = NULL;
|
||||
|
||||
new = strtonum(tok, 0, 2 << 31, &err);
|
||||
new = strtonum(tok, 0, (long long)2 << 31, &err);
|
||||
if (err)
|
||||
goto fail;
|
||||
}
|
||||
@@ -340,16 +340,13 @@ static void parse_dynamic(char *line, time_t mtime)
|
||||
if (MATCH_CMD(line, "#", x))
|
||||
return;
|
||||
|
||||
/* Monitored daemon, will be respawned on exit, as
|
||||
* long as the (optional) service callback returns
|
||||
* non-zero */
|
||||
/* Monitored daemon, will be respawned on exit */
|
||||
if (MATCH_CMD(line, "service ", x)) {
|
||||
service_register(SVC_TYPE_SERVICE, x, mtime, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
/* One-shot task, will not be respawned. Only runs if
|
||||
* the (optional) service callback returns true */
|
||||
/* One-shot task, will not be respawned */
|
||||
if (MATCH_CMD(line, "task ", x)) {
|
||||
service_register(SVC_TYPE_TASK, x, mtime, NULL);
|
||||
return;
|
||||
|
||||
+21
-16
@@ -1,4 +1,4 @@
|
||||
AC_INIT(Finit, 3.0-rc1, https://github.com/troglobit/finit/issues, finit, http://troglobit.com/finit.html)
|
||||
AC_INIT(Finit, 3.0-rc2, https://github.com/troglobit/finit/issues, finit, http://troglobit.com/finit.html)
|
||||
AM_INIT_AUTOMAKE([1.11 foreign no-dist-gzip dist-xz subdir-objects])
|
||||
AM_SILENT_RULES([yes])
|
||||
|
||||
@@ -33,7 +33,7 @@ AC_TYPE_UINT16_T
|
||||
AC_TYPE_UINT32_T
|
||||
|
||||
# Check for required libraries
|
||||
PKG_CHECK_MODULES([uev], [libuev >= 1.4.2])
|
||||
PKG_CHECK_MODULES([uev], [libuev >= 1.5.2])
|
||||
PKG_CHECK_MODULES([lite], [libite >= 1.8.2])
|
||||
|
||||
# Check for configured Finit features
|
||||
@@ -41,12 +41,18 @@ AC_ARG_ENABLE(emergency_shell,
|
||||
AS_HELP_STRING([--enable-emergency-shell], [Experimental emergency fallback at boot.
|
||||
Only use this for debugging very early boot problems with Finit.]))
|
||||
|
||||
AC_ARG_ENABLE(fallback_shell,
|
||||
AS_HELP_STRING([--enable-fallback-shell], [Start a shell if no TTYs can start.]))
|
||||
|
||||
AC_ARG_ENABLE(rw-rootfs,
|
||||
AS_HELP_STRING([--enable-rw-rootfs], [Remount / R/W at boot, usually not for embedded]))
|
||||
|
||||
AC_ARG_ENABLE(silent,
|
||||
AS_HELP_STRING([--enable-silent], [Completely silent operation, not even boot messages]))
|
||||
|
||||
AC_ARG_ENABLE(watchdog,
|
||||
AS_HELP_STRING([--enable-watchdog], [Enable built-in watchdog, uses /dev/watchdog]))
|
||||
|
||||
AC_ARG_ENABLE(inetd,
|
||||
AS_HELP_STRING([--disable-inetd], [Disable built-in inetd super server, default enabled]))
|
||||
|
||||
@@ -97,10 +103,6 @@ AC_ARG_WITH(console,
|
||||
AS_HELP_STRING([--with-console=DEV], [Console to use, default: /dev/console]),
|
||||
[console=$withval], [console=/dev/console])
|
||||
|
||||
AC_ARG_WITH(shell,
|
||||
AS_HELP_STRING([--with-shell=PATH], [Fallback shell to use, default: /bin/sh]),
|
||||
[shell=$withval], [shell=/bin/sh])
|
||||
|
||||
AC_ARG_WITH(username,
|
||||
AS_HELP_STRING([--with-username=USER], [User for 'startx' .conf option, default: root]),
|
||||
[username=$withval], [username=root])
|
||||
@@ -124,6 +126,9 @@ AC_ARG_WITH(random-seed,
|
||||
AS_IF([test "x$enable_emergency_shell" = "xyes"], [
|
||||
AC_DEFINE(EMERGENCY_SHELL, 1, [Fork off init and let PID 1 wait and start /bin/sh if init crashes.])])
|
||||
|
||||
AS_IF([test "x$enable_fallback_shell" = "xyes"], [
|
||||
AC_DEFINE(FALLBACK_SHELL, 1, [Start /bin/sh on console if no TTYs.])])
|
||||
|
||||
AS_IF([test "x$enable_rw_rootfs" = "xyes"], [
|
||||
AC_DEFINE(REMOUNT_ROOTFS, 1, [Remount / as rw at boot])])
|
||||
|
||||
@@ -132,14 +137,18 @@ AS_IF([test "x$enable_silent" = "xyes"], [
|
||||
], [
|
||||
AC_DEFINE(SILENT_MODE, 0, [Normal output, default])])
|
||||
|
||||
AS_IF([test "x$enable_watchdog" = "xyes"], [
|
||||
AC_DEFINE(BUILTIN_WATCHDOG, 1, [Enable built-in watchdog, kicks on /dev/watchdog])])
|
||||
|
||||
### Disable features ###########################################################################
|
||||
AS_IF([test "x$enable_inetd" != "xno"], enable_inetd="yes", [
|
||||
AS_IF([test "x$enable_inetd" != "xno"],
|
||||
enable_inetd="yes", [
|
||||
AC_DEFINE(INETD_DISABLED, 1, [Disable built-in inetd])])
|
||||
|
||||
AS_IF([test "x$enable_quiet" != "xno"], [
|
||||
AC_DEFINE(QUIET_MODE, 0, [Will print stopping/starting/etc messages at runtime])
|
||||
AC_DEFINE(QUIET_MODE, 1, [Silent, after initial boot, no stopping/starting messages. Default: 1])
|
||||
], [
|
||||
AC_DEFINE(QUIET_MODE, 1, [Silent at runtime, after initial boot, default])])
|
||||
AC_DEFINE(QUIET_MODE, 0, [Silent, after initial boot, no stopping/starting messages. Default: 1])])
|
||||
|
||||
### With features ##############################################################################
|
||||
AS_IF([test "x$with_fifo" != "xno"], [
|
||||
@@ -176,11 +185,6 @@ AS_IF([test "x$with_console" != "xno"], [
|
||||
console=/dev/console])])
|
||||
AC_DEFINE_UNQUOTED(CONSOLE, "$console", [Default console to use])
|
||||
|
||||
AS_IF([test "x$with_shell" != "xno"], [
|
||||
AS_IF([test "x$shell" = "xyes"], [
|
||||
shell=/bin/sh])])
|
||||
AC_DEFINE_UNQUOTED(FALLBACK_SHELL, "$shell", [Used if no login getty])
|
||||
|
||||
AS_IF([test "x$with_username" != "xno"], [
|
||||
AS_IF([test "x$username" = "xyes"], [
|
||||
username=root])])
|
||||
@@ -203,8 +207,9 @@ AS_IF([test "x$with_random_seed" != "xno"], [
|
||||
AC_DEFINE_UNQUOTED(RANDOMSEED, "$lurvig", [Improve random at boot by seeding it with sth from before.])])
|
||||
|
||||
# Control build with automake flags
|
||||
AM_CONDITIONAL(STATIC, [test "x$enable_static" = "xyes"])
|
||||
AM_CONDITIONAL(INETD, [test "x$enable_inetd" = "xyes"])
|
||||
AM_CONDITIONAL(STATIC, [test "x$enable_static" = "xyes"])
|
||||
AM_CONDITIONAL(INETD, [test "x$enable_inetd" = "xyes"])
|
||||
AM_CONDITIONAL(WATCHDOGD, [test "x$enable_watchdog" = "xyes"])
|
||||
|
||||
# Generate all files
|
||||
AC_OUTPUT
|
||||
|
||||
@@ -166,6 +166,9 @@ The `run`, `task`, `service`, or `inetd` stanzas also allow the keyword
|
||||
`log` to redirect `stderr` and `stdout` of the application to syslog,
|
||||
using `logger`.
|
||||
|
||||
Worth noting is that conditions is allowed for all these stanzas. For a
|
||||
detailed description, see the [Conditions](conditions.md) document.
|
||||
|
||||
|
||||
/etc/finit.d
|
||||
------------
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
Finit Signals
|
||||
=============
|
||||
|
||||
Finit is often used on embedded and small Linux systems with BusyBox.
|
||||
Though Finit comes with its own tools for (poweroff, halt, reboot), for
|
||||
compatibility with the existing BusyBox toolset the following signals
|
||||
have been adopted:
|
||||
|
||||
* `SIGUSR1`
|
||||
Same effect as `finit q`, reloads all *.conf files in `/etc/finit.d/`
|
||||
* `SIGUSR1`
|
||||
Calls shutdown hooks, including HOOK_SHUTDOWN, stops all running
|
||||
processes, and unmounts all file systems. Then tells kernel to
|
||||
halt. Most people these days want SIGUSR2 though.
|
||||
|
||||
SysV init and systemd use this to re-open their FIFO/D-Bus.
|
||||
* `SIGUSR2`
|
||||
Like SIGUSR1, but tell kernel to power-off the system, if ACPI
|
||||
or similar exists to actually do this. If the kernel fails
|
||||
power-off, Finit falls back to halt.
|
||||
|
||||
SysV init N/A, systemd dumps its internal state to log.
|
||||
* `SIGTERM`
|
||||
Like `SIGUSR1`, but tell kernel to reboot the system when done.
|
||||
|
||||
SysV init N/A, systemd rexecutes itself.
|
||||
* `SIGINT`
|
||||
Sent from kernel when the CTRL-ALT-DEL key combo is pressed.
|
||||
SysV init and systemd default to reboot with `shutdown -r`.
|
||||
Finit currently forwards this to `SIGTERM`.
|
||||
* `SIGPWR`
|
||||
Sent from a power daemon, like `powstatd(8)`, on changes to the
|
||||
UPS status. Traditionally SysV init read /etc/powerstatus and
|
||||
acted on "OK", "FAIL", or "LOW" and then removed the file.
|
||||
Finit currently forwards this to `SIGUSR2`.
|
||||
|
||||
<!--
|
||||
-- Local Variables:
|
||||
-- mode: markdown
|
||||
-- End:
|
||||
-->
|
||||
@@ -100,13 +100,11 @@ int run(char *cmd)
|
||||
|
||||
pid = fork();
|
||||
if (0 == pid) {
|
||||
int i;
|
||||
FILE *fp;
|
||||
struct sigaction sa;
|
||||
|
||||
/* Reset signal handlers that were set by the parent process */
|
||||
for (i = 1; i < NSIG; i++)
|
||||
DFLSIG(sa, i, 0);
|
||||
sig_unblock();
|
||||
setsid();
|
||||
|
||||
/* Always redirect stdio for run() */
|
||||
fp = fopen("/dev/null", "w");
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
#include "config.h" /* Generated by configure script */
|
||||
|
||||
#include <ctype.h>
|
||||
#include <glob.h>
|
||||
#include <dirent.h>
|
||||
#ifdef HAVE_FSTAB_H
|
||||
#include <fstab.h>
|
||||
@@ -46,10 +45,12 @@
|
||||
#include "sm.h"
|
||||
#include "tty.h"
|
||||
#include "utmp-api.h"
|
||||
#include "watchdog.h"
|
||||
|
||||
int debug = 0;
|
||||
int quiet = QUIET_MODE; /* Delayed disable of silent mode. */
|
||||
int silent = SILENT_MODE; /* Completely silent, including boot */
|
||||
int wdogpid = 0; /* No watchdog by default */
|
||||
int runlevel = 0; /* Bootstrap 'S' */
|
||||
int cfglevel = RUNLEVEL; /* Fallback if no configured runlevel */
|
||||
int prevlevel = -1;
|
||||
@@ -119,26 +120,7 @@ static int fsck(int pass)
|
||||
|
||||
static void networking(void)
|
||||
{
|
||||
size_t i;
|
||||
glob_t gl;
|
||||
FILE *fp;
|
||||
char buf[160];
|
||||
|
||||
/* Setup kernel specific settings, e.g. allow broadcast ping, etc. */
|
||||
glob("/run/sysctl.d/*.conf", 0, NULL, &gl);
|
||||
glob("/etc/sysctl.d/*.conf", GLOB_APPEND, NULL, &gl);
|
||||
glob("/usr/local/lib/sysctl.d/*.conf", GLOB_APPEND, NULL, &gl);
|
||||
glob("/usr/lib/sysctl.d/*.conf", GLOB_APPEND, NULL, &gl);
|
||||
glob("/lib/sysctl.d/*.conf", GLOB_APPEND, NULL, &gl);
|
||||
glob("/mnt/sysctl.d/*.conf", GLOB_APPEND, NULL, &gl);
|
||||
glob("/etc/sysctl.conf", GLOB_APPEND, NULL, &gl);
|
||||
if (gl.gl_pathc > 0) {
|
||||
for (i = 0; i < gl.gl_pathc; i++) {
|
||||
snprintf(buf, sizeof(buf), "/sbin/sysctl -e -p %s >/dev/null", gl.gl_pathv[i]);
|
||||
run(buf);
|
||||
}
|
||||
globfree(&gl);
|
||||
}
|
||||
|
||||
/* Run user network start script if enabled */
|
||||
if (network) {
|
||||
@@ -149,7 +131,8 @@ static void networking(void)
|
||||
/* Debian/Ubuntu/Busybox interfaces file */
|
||||
fp = fopen("/etc/network/interfaces", "r");
|
||||
if (fp) {
|
||||
i = 0;
|
||||
int i = 0;
|
||||
char buf[160];
|
||||
|
||||
/* Bring up all 'auto' interfaces */
|
||||
while (fgets(buf, sizeof(buf), fp)) {
|
||||
@@ -232,7 +215,6 @@ static void emergency_shell(void)
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
int err;
|
||||
char *devfsd;
|
||||
uev_ctx_t loop;
|
||||
|
||||
@@ -325,7 +307,13 @@ int main(int argc, char* argv[])
|
||||
else
|
||||
devfsd = "/lib/systemd/systemd-udevd --daemon";
|
||||
}
|
||||
|
||||
run_interactive(devfsd, "Populating device tree");
|
||||
if (fexist("/sbin/udevadm")) {
|
||||
run("/sbin/udevadm trigger --action=add --type=subsystems");
|
||||
run("/sbin/udevadm trigger --action=add --type=devices");
|
||||
run("/sbin/udevadm settle --timeout=120");
|
||||
}
|
||||
|
||||
/*
|
||||
* Load plugins first, finit.conf may contain references to
|
||||
@@ -338,6 +326,11 @@ int main(int argc, char* argv[])
|
||||
*/
|
||||
conf_parse_config();
|
||||
|
||||
/*
|
||||
* Start built-in watchdog as soon as possible, if enabled
|
||||
*/
|
||||
watchdog(argv[0]);
|
||||
|
||||
/* Set hostname as soon as possible, for syslog et al. */
|
||||
set_hostname(&hostname);
|
||||
|
||||
@@ -362,19 +355,12 @@ int main(int argc, char* argv[])
|
||||
plugin_run_hooks(HOOK_ROOTFS_UP);
|
||||
|
||||
umask(0);
|
||||
print_desc("Mounting filesystems", NULL);
|
||||
|
||||
err = run("/bin/mount -na");
|
||||
print_result(err);
|
||||
if (err)
|
||||
if (run_interactive("/bin/mount -na", "Mounting filesystems"))
|
||||
plugin_run_hooks(HOOK_MOUNT_ERROR);
|
||||
|
||||
run("/sbin/swapon -ea");
|
||||
umask(0022);
|
||||
|
||||
/* Cleanup of stale files, if any still linger on. */
|
||||
run_interactive("rm -rf /tmp/* /var/run/* /var/lock/*", "Cleaning up temporary directories");
|
||||
|
||||
/* Base FS up, enable standard SysV init signals */
|
||||
sig_setup(&loop);
|
||||
|
||||
@@ -410,11 +396,14 @@ int main(int argc, char* argv[])
|
||||
if (runparts && fisdir(runparts)) {
|
||||
_d("Running startup scripts in %s ...", runparts);
|
||||
run_parts(runparts, NULL);
|
||||
service_reload_dynamic();
|
||||
}
|
||||
|
||||
/* Convenient SysV compat for when you just don't care ... */
|
||||
if (!access(FINIT_RC_LOCAL, X_OK))
|
||||
if (!access(FINIT_RC_LOCAL, X_OK)) {
|
||||
run_interactive(FINIT_RC_LOCAL, "Calling %s", FINIT_RC_LOCAL);
|
||||
service_reload_dynamic();
|
||||
}
|
||||
|
||||
/* Hooks that should run at the very end */
|
||||
plugin_run_hooks(HOOK_SYSTEM_UP);
|
||||
|
||||
@@ -63,10 +63,11 @@
|
||||
#define INIT_CMD_START_SVC 10
|
||||
#define INIT_CMD_STOP_SVC 11
|
||||
#define INIT_CMD_RELOAD_SVC 12 /* SIGHUP service */
|
||||
#define INIT_CMD_RESTART_SVC 13 /* STOP + START service */
|
||||
#define INIT_CMD_RESTART_SVC 13 /* STOP + START service */
|
||||
#define INIT_CMD_QUERY_INETD 14
|
||||
#define INIT_CMD_EMIT 15
|
||||
#define INIT_CMD_GET_RUNLEVEL 16
|
||||
#define INIT_CMD_WDOG_HELLO 128 /* Watchdog register and hello */
|
||||
#define INIT_CMD_NACK 254
|
||||
#define INIT_CMD_ACK 255
|
||||
|
||||
@@ -81,6 +82,7 @@ struct init_request {
|
||||
extern int debug;
|
||||
extern int quiet;
|
||||
extern int silent;
|
||||
extern int wdogpid;
|
||||
extern int runlevel;
|
||||
extern int cfglevel;
|
||||
extern int prevlevel;
|
||||
@@ -93,8 +95,6 @@ extern char *runparts;
|
||||
extern char *console;
|
||||
extern uev_ctx_t *ctx;
|
||||
|
||||
extern char *__progname;
|
||||
|
||||
#endif /* FINIT_H_ */
|
||||
|
||||
/**
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include <stdio.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <sys/ttydefaults.h> /* Not included by default in musl libc */
|
||||
#include <termios.h>
|
||||
|
||||
#include "finit.h"
|
||||
@@ -73,13 +74,34 @@ static void stty(int fd, speed_t speed)
|
||||
cfsetispeed(&term, speed);
|
||||
cfsetospeed(&term, speed);
|
||||
tcsetattr(fd, TCSAFLUSH, &term);
|
||||
|
||||
tcflush(fd, TCIOFLUSH);
|
||||
|
||||
/* Clear screen -- disabled until we decide on config to disable/enable */
|
||||
//print("\033[r\033[H\033[J");
|
||||
}
|
||||
/* Disable modem specific flags */
|
||||
term.c_cflag &= (0|CSTOPB|PARENB|PARODD);
|
||||
term.c_cflag &= ~CRTSCTS;
|
||||
term.c_cflag |= CLOCAL;
|
||||
|
||||
/* Timeouts, minimum chars and default flags */
|
||||
term.c_cc[VTIME] = 0;
|
||||
term.c_cc[VMIN] = 1;
|
||||
term.c_iflag = ICRNL|IXON|IXOFF;
|
||||
term.c_oflag = OPOST|ONLCR;
|
||||
term.c_cflag |= CS8|CREAD|HUPCL|CBAUDEX;
|
||||
term.c_lflag |= ISIG|ICANON|ECHO|ECHOE|ECHOK|ECHOKE;
|
||||
|
||||
/* Reset special characters to defaults */
|
||||
term.c_cc[VINTR] = CTRL('C');
|
||||
term.c_cc[VQUIT] = CTRL('\\');
|
||||
term.c_cc[VEOF] = CTRL('D');
|
||||
term.c_cc[VEOL] = '\n';
|
||||
term.c_cc[VKILL] = CTRL('U');
|
||||
term.c_cc[VERASE] = CERASE;
|
||||
tcsetattr(fd, TCSANOW, &term);
|
||||
|
||||
/* Clear screen in silent mode */
|
||||
if (silent)
|
||||
print("\033[r\033[H\033[J");
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse and display a line from /etc/issue
|
||||
|
||||
@@ -181,11 +181,8 @@ int print_result(int fail)
|
||||
}
|
||||
|
||||
/*
|
||||
* Log to stderr until syslogd has started, then openlog() and continue
|
||||
* logging as a regular daemon.
|
||||
*
|
||||
* TODO: Log to /dev/kmsg instead of stderr until syslogd has started
|
||||
* Need to convert facility+prio => "<VAL> msg"
|
||||
* Log to /dev/kmsg until syslogd has started, then openlog()
|
||||
* and continue logging as a regular daemon.
|
||||
*/
|
||||
void logit(int prio, const char *fmt, ...)
|
||||
{
|
||||
@@ -197,12 +194,15 @@ void logit(int prio, const char *fmt, ...)
|
||||
|
||||
fp = fopen("/dev/kmsg", "w");
|
||||
if (fp) {
|
||||
if (debug)
|
||||
prio = LOG_ERR;
|
||||
|
||||
fprintf(fp, "<%d>finit[1]:", LOG_DAEMON | prio);
|
||||
vfprintf(fp, fmt, ap);
|
||||
fclose(fp);
|
||||
} else {
|
||||
fprintf(stderr, "Failed opening /dev/kmsg for appending ...\n");
|
||||
if (prio <= LOG_ERR)
|
||||
if (debug || prio <= LOG_ERR)
|
||||
vfprintf(stderr, fmt, ap);
|
||||
}
|
||||
va_end(ap);
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
_______ __ _____ ___ __ ___________ _______
|
||||
/" "||" \ (\" \|" \ |" \(" _ ")/" __ )
|
||||
(: ______)|| | |.\\ \ | || |)__/ \\__/(__/ _) ./
|
||||
\/ | |: | |: \. \\ | |: | \\_ / / //
|
||||
// ___) |. | |. \ \. | |. | |. | __ \_ \\
|
||||
(: ( /\ |\| \ \ | /\ |\ \: | (: \__) :\
|
||||
\__/ (__\_|_)\___|\____\)(__\_|_) \__| \_______)
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 23 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 8.6 KiB |
@@ -321,9 +321,8 @@ void inetd_stop(inetd_t *inetd)
|
||||
}
|
||||
}
|
||||
|
||||
static struct servent *getent_service(char *service, char *proto)
|
||||
static struct servent *fallback_service(char *service, char *proto)
|
||||
{
|
||||
#ifdef ENABLE_STATIC
|
||||
int service_num;
|
||||
static struct servent lfs;
|
||||
|
||||
@@ -339,29 +338,50 @@ static struct servent *getent_service(char *service, char *proto)
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct servent *getent_service(char *service, char *proto)
|
||||
{
|
||||
struct servent *ent;
|
||||
|
||||
#ifdef ENABLE_STATIC
|
||||
ent = fallback_service(service, proto);
|
||||
#else
|
||||
return getservbyname(service, proto);
|
||||
ent = getservbyname(service, proto);
|
||||
if (!ent)
|
||||
ent = fallback_service(service, proto);
|
||||
#endif
|
||||
return ent;
|
||||
}
|
||||
|
||||
static struct protoent *fallback_proto(char *proto)
|
||||
{
|
||||
int proto_num;
|
||||
static struct protoent lfp;
|
||||
|
||||
proto_num = fgetint("/etc/protocols", " \n\t", proto);
|
||||
if (proto_num > 0) {
|
||||
lfp.p_name = proto;
|
||||
lfp.p_proto = proto_num;
|
||||
|
||||
return &lfp;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct protoent *getent_proto(char *proto)
|
||||
{
|
||||
struct protoent *ent;
|
||||
|
||||
#ifdef ENABLE_STATIC
|
||||
int proto_num;
|
||||
static struct protoent lfp;
|
||||
|
||||
proto_num = fgetint("/etc/protocols", " \n\t", proto);
|
||||
if (proto_num > 0) {
|
||||
lfp.p_name = proto;
|
||||
lfp.p_proto = proto_num;
|
||||
|
||||
return &lfp;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
ent = fallback_proto(proto);
|
||||
#else
|
||||
return getprotobyname(proto);
|
||||
ent = getprotobyname(proto);
|
||||
if (!ent)
|
||||
ent = fallback_proto(proto);
|
||||
#endif
|
||||
return ent;
|
||||
}
|
||||
|
||||
static int getent(char *service, char *proto, struct servent **sv, struct protoent **pv)
|
||||
@@ -615,6 +635,23 @@ int inetd_filter_str(inetd_t *inetd, char *str, size_t len)
|
||||
return 0;
|
||||
}
|
||||
|
||||
svc_t *inetd_find_svc(char *path, char *service, char *proto)
|
||||
{
|
||||
svc_t *svc;
|
||||
|
||||
for (svc = svc_inetd_iterator(1); svc; svc = svc_inetd_iterator(0)) {
|
||||
if (strncmp(path, svc->cmd, strlen(svc->cmd)))
|
||||
continue;
|
||||
|
||||
if (inetd_match(&svc->inetd, service, proto)) {
|
||||
_d("Found a matching inetd svc for %s %s %s", path, service, proto);
|
||||
return svc;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is called to add a new, unique, inetd service. When an
|
||||
* ifname is given as argument this means *only* run service on this
|
||||
|
||||
@@ -54,22 +54,23 @@ typedef struct {
|
||||
TAILQ_HEAD(, inetd_filter) filters;
|
||||
} inetd_t;
|
||||
|
||||
int inetd_check_loop (struct sockaddr *sa, socklen_t len, char *name);
|
||||
int inetd_check_loop(struct sockaddr *sa, socklen_t len, char *name);
|
||||
|
||||
int inetd_start (inetd_t *inetd);
|
||||
void inetd_stop (inetd_t *inetd);
|
||||
int inetd_start (inetd_t *inetd);
|
||||
void inetd_stop (inetd_t *inetd);
|
||||
|
||||
int inetd_new (inetd_t *inetd, char *name, char *service, char *proto,
|
||||
int forking, svc_t *svc);
|
||||
int inetd_del (inetd_t *inetd);
|
||||
int inetd_new (inetd_t *inetd, char *name, char *service, char *proto, int forking, svc_t *svc);
|
||||
int inetd_del (inetd_t *inetd);
|
||||
|
||||
int inetd_match (inetd_t *inetd, char *service, char *proto);
|
||||
int inetd_filter_str (inetd_t *inetd, char *str, size_t len);
|
||||
svc_t *inetd_find_svc (char *path, char *service, char *proto);
|
||||
|
||||
int inetd_flush (inetd_t *inetd);
|
||||
int inetd_allow (inetd_t *inetd, char *ifname);
|
||||
int inetd_deny (inetd_t *inetd, char *ifname);
|
||||
int inetd_is_allowed (inetd_t *inetd, char *ifname);
|
||||
int inetd_match (inetd_t *inetd, char *service, char *proto);
|
||||
int inetd_filter_str(inetd_t *inetd, char *str, size_t len);
|
||||
|
||||
int inetd_flush (inetd_t *inetd);
|
||||
int inetd_allow (inetd_t *inetd, char *ifname);
|
||||
int inetd_deny (inetd_t *inetd, char *ifname);
|
||||
int inetd_is_allowed(inetd_t *inetd, char *ifname);
|
||||
|
||||
#endif /* FINIT_INETD_H_ */
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
#include "cond.h"
|
||||
#include "helpers.h"
|
||||
#include "service.h"
|
||||
#include "util.h"
|
||||
#include "utmp-api.h"
|
||||
|
||||
#define _PATH_COND _PATH_VARRUN "finit/cond/"
|
||||
@@ -439,7 +440,7 @@ static int usage(int rc)
|
||||
" halt Halt system\n"
|
||||
" poweroff Halt and power off system\n"
|
||||
" utmp show Raw dump of UTMP/WTMP db\n"
|
||||
" version Show Finit version\n\n", __progname);
|
||||
" version Show Finit version\n\n", prognm);
|
||||
|
||||
return rc;
|
||||
}
|
||||
@@ -471,6 +472,7 @@ int main(int argc, char *argv[])
|
||||
{NULL, 0, NULL, 0}
|
||||
};
|
||||
|
||||
progname(argv[0]);
|
||||
while ((c = getopt_long(argc, argv, "dh?v", long_options, NULL)) != EOF) {
|
||||
switch(c) {
|
||||
case 'h':
|
||||
|
||||
+3
-2
@@ -1,11 +1,12 @@
|
||||
AM_LDFLAGS = -module -avoid-version -shared
|
||||
AM_CFLAGS = -W -Wall -Wextra -std=gnu99
|
||||
AM_CPPFLAGS = -U_FORTIFY_SOURCE
|
||||
AM_CPPFLAGS += -D_XOPEN_SOURCE=600 -D_BSD_SOURCE -D_GNU_SOURCE -D_DEFAULT_SOURCE
|
||||
AM_CPPFLAGS += $(lite_CFLAGS)
|
||||
|
||||
if STATIC
|
||||
noinst_LTLIBRARIES = libplug.la
|
||||
libplug_la_SOURCES = bootmisc.c hwclock.c initctl.c pidfile.c tty.c urandom.c
|
||||
libplug_la_SOURCES = bootmisc.c hwclock.c initctl.c pidfile.c procps.c tty.c urandom.c
|
||||
|
||||
if BUILD_ALSA_UTILS_PLUGIN
|
||||
libplug_la_SOURCES += alsa-utils.c
|
||||
@@ -50,7 +51,7 @@ libplug_la_SOURCES += resolvconf.c
|
||||
endif
|
||||
|
||||
else
|
||||
pkglib_LTLIBRARIES = bootmisc.la hwclock.la initctl.la pidfile.la tty.la urandom.la
|
||||
pkglib_LTLIBRARIES = bootmisc.la hwclock.la initctl.la pidfile.la procps.la tty.la urandom.la
|
||||
|
||||
if BUILD_ALSA_UTILS_PLUGIN
|
||||
pkglib_LTLIBRARIES += alsa-utils.la
|
||||
|
||||
+69
-1
@@ -21,6 +21,8 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <ftw.h>
|
||||
#include <mntent.h>
|
||||
#include <string.h>
|
||||
#include <lite/lite.h>
|
||||
|
||||
@@ -30,12 +32,73 @@
|
||||
#include "../plugin.h"
|
||||
#include "../utmp-api.h"
|
||||
|
||||
static int is_tmpfs(char *path)
|
||||
{
|
||||
int tmpfs = 0;
|
||||
FILE *fp;
|
||||
char *dir;
|
||||
struct mntent *mnt;
|
||||
|
||||
/* If path is a symlink, check what it resolves to */
|
||||
dir = realpath(path, NULL);
|
||||
if (!dir)
|
||||
return 0; /* Outlook not so good */
|
||||
|
||||
fp = setmntent("/proc/mounts", "r");
|
||||
if (!fp) {
|
||||
free(dir);
|
||||
return 0; /* Dunno, maybe not */
|
||||
}
|
||||
|
||||
while ((mnt = getmntent(fp))) {
|
||||
if (!strcmp(dir, mnt->mnt_dir))
|
||||
break;
|
||||
}
|
||||
|
||||
if (mnt && !strcmp("tmpfs", mnt->mnt_type))
|
||||
tmpfs = 1;
|
||||
|
||||
endmntent(fp);
|
||||
free(dir);
|
||||
|
||||
return tmpfs;
|
||||
}
|
||||
|
||||
static void create(char *path, mode_t mode, uid_t uid, gid_t gid)
|
||||
{
|
||||
if (touch(path) || chmod(path, mode) || chown(path, uid, gid))
|
||||
_w("Failed creating %s properl.", path);
|
||||
}
|
||||
|
||||
static int do_clean(const char *fpath, const struct stat *UNUSED(sb), int UNUSED(tflag), struct FTW *ftwbuf)
|
||||
{
|
||||
if (ftwbuf->level == 0)
|
||||
return 1;
|
||||
|
||||
_d("Removing %s ...", fpath);
|
||||
(void)remove(fpath);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* We can safely skip tmpfs, nothing to clean from previous boot there */
|
||||
static void bootclean(void)
|
||||
{
|
||||
char *dir[] = {
|
||||
"/tmp/",
|
||||
"/var/run/",
|
||||
"/var/lock/",
|
||||
NULL
|
||||
};
|
||||
|
||||
for (int i = 0; dir[i]; i++) {
|
||||
if (is_tmpfs(dir[i]))
|
||||
continue;
|
||||
|
||||
nftw(dir[i], do_clean, 20, FTW_DEPTH);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Setup standard FHS 2.3 structure in /var, and write runlevel to UTMP
|
||||
*/
|
||||
@@ -43,7 +106,11 @@ static void setup(void *UNUSED(arg))
|
||||
{
|
||||
int gid;
|
||||
|
||||
/* Cleanup stale files, if any still linger on. */
|
||||
bootclean();
|
||||
|
||||
_d("Setting up FHS structure in /var ...");
|
||||
umask(0);
|
||||
makedir("/var/cache", 0755);
|
||||
makedir("/var/games", 0755);
|
||||
makedir("/var/lib", 0755);
|
||||
@@ -60,7 +127,6 @@ static void setup(void *UNUSED(arg))
|
||||
makedir("/var/lock", 1777);
|
||||
makedir("/var/run", 0755);
|
||||
}
|
||||
makedir("/var/lock/subsys",0755); /* Needed by D-Bus plugin */
|
||||
makedir("/var/log", 0755);
|
||||
makedir("/var/mail", 0755);
|
||||
makedir("/var/opt", 0755);
|
||||
@@ -104,6 +170,8 @@ static void setup(void *UNUSED(arg))
|
||||
makedir("/var/run/sshd", 01755); /* OpenSSH */
|
||||
makefifo("/dev/xconsole", 0640); /* sysklogd */
|
||||
chown("/dev/xconsole", 0, getgroup("tty"));
|
||||
|
||||
umask(022);
|
||||
}
|
||||
|
||||
static plugin_t plugin = {
|
||||
|
||||
+14
-8
@@ -30,25 +30,32 @@
|
||||
#define NAME "chargen"
|
||||
#define PATTERN "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ "
|
||||
|
||||
static char *generator(char *buf, size_t len)
|
||||
static char *generator(char *buf, size_t buflen)
|
||||
{
|
||||
size_t num;
|
||||
size_t num, len, width = 72;
|
||||
static size_t pos = 0;
|
||||
const char pattern[] = PATTERN;
|
||||
|
||||
len = 72;
|
||||
if (buflen < width)
|
||||
width = buflen;
|
||||
|
||||
len = width;
|
||||
if (len + 3 > buflen)
|
||||
len = buflen - 3;
|
||||
if (pos + len > sizeof(pattern)) {
|
||||
num = sizeof(pattern) - pos;
|
||||
len -= num;
|
||||
} else {
|
||||
num = 72;
|
||||
num = width;
|
||||
if (num + 3 > buflen)
|
||||
num = buflen - 3;
|
||||
len = 0;
|
||||
}
|
||||
|
||||
strncpy(&buf[0], &pattern[pos], num--);
|
||||
strncpy(buf, &pattern[pos], num--);
|
||||
if (len++)
|
||||
strncpy(&buf[num], pattern, len);
|
||||
strcat(buf, "\r\n");
|
||||
strlcat(buf, "\r\n", width);
|
||||
|
||||
if (++pos >= sizeof(pattern) - 1)
|
||||
pos = 0;
|
||||
@@ -75,10 +82,9 @@ static int send_peer(int sd, char *buf, ssize_t len, struct sockaddr *sa, sockle
|
||||
return sendto(sd, pattern, strlen(pattern), MSG_DONTWAIT, sa, sa_len);
|
||||
}
|
||||
|
||||
static int cb(int type)
|
||||
static int cb(int UNUSED(type))
|
||||
{
|
||||
int sd = STDIN_FILENO;
|
||||
ssize_t len;
|
||||
char buf[BUFSIZ];
|
||||
struct sockaddr_storage sa;
|
||||
socklen_t sa_len = sizeof(sa);
|
||||
|
||||
+1
-1
@@ -64,7 +64,7 @@ static int send_peer(int sd, char *buf, ssize_t len, struct sockaddr *sa, sockle
|
||||
return sendto(sd, now, strlen(now), MSG_DONTWAIT, sa, sa_len);
|
||||
}
|
||||
|
||||
static int cb(int type)
|
||||
static int cb(int UNUSED(type))
|
||||
{
|
||||
int sd = STDIN_FILENO;
|
||||
char buf[BUFSIZ];
|
||||
|
||||
@@ -31,12 +31,17 @@
|
||||
|
||||
static void setup(void *UNUSED(arg))
|
||||
{
|
||||
umask(0);
|
||||
|
||||
_d("Starting D-Bus ...");
|
||||
makedir("/var/run/dbus", 0755);
|
||||
makedir("/var/lock/subsys", 0755);
|
||||
makedir("/var/lock/subsys/messagebus", 0755);
|
||||
run("dbus-uuidgen --ensure");
|
||||
erase("/var/run/dbus/pid");
|
||||
run_interactive("dbus-daemon --system", "Starting D-Bus");
|
||||
|
||||
umask(022);
|
||||
}
|
||||
|
||||
static plugin_t plugin = {
|
||||
|
||||
+1
-1
@@ -27,7 +27,7 @@
|
||||
|
||||
#include "../plugin.h"
|
||||
|
||||
static int cb(int type)
|
||||
static int cb(int UNUSED(type))
|
||||
{
|
||||
int sd = STDIN_FILENO;
|
||||
char buf[BUFSIZ];
|
||||
|
||||
+10
-21
@@ -39,13 +39,6 @@
|
||||
#include "../sig.h"
|
||||
#include "../service.h"
|
||||
|
||||
/*
|
||||
* Old-style SysV shutdown sends a setenv cmd INIT_HALT with "=HALT",
|
||||
* "=POWERDOWN", or "" to cancel shutdown, before requesting change to
|
||||
* runlevel 6 over the /dev/initctl FIFO.
|
||||
*/
|
||||
shutop_t halt = SHUT_DEFAULT;
|
||||
|
||||
static void parse(void *arg, int fd, int events);
|
||||
static void setup(void *arg);
|
||||
|
||||
@@ -99,11 +92,15 @@ static void set_env(char *data)
|
||||
}
|
||||
|
||||
/*
|
||||
* Standard reboot/shutdown utilities talk to init using /dev/initctl.
|
||||
* Standard reboot/shutdown utilities talk to init using /run/initctl.
|
||||
* We should check if the fifo was recreated and reopen it.
|
||||
*
|
||||
* For SysV compatibility the default is to halt the system when issuing
|
||||
* `init 0`, unless INIT_HALT=POWERDOWN, as performed by the SysV utils.
|
||||
*/
|
||||
static void parse(void *UNUSED(arg), int fd, int UNUSED(events))
|
||||
{
|
||||
int lvl;
|
||||
struct init_request rq;
|
||||
|
||||
while (1) {
|
||||
@@ -132,25 +129,17 @@ static void parse(void *UNUSED(arg), int fd, int UNUSED(events))
|
||||
switch (rq.cmd) {
|
||||
case INIT_CMD_RUNLVL:
|
||||
switch (rq.runlevel) {
|
||||
case '0':
|
||||
_d("Halting system (SIGUSR1 or SIGUSR2)");
|
||||
do_shutdown(halt);
|
||||
break;
|
||||
|
||||
case 's':
|
||||
case 'S':
|
||||
rq.runlevel = '1';
|
||||
/* Fall through to regular processing */
|
||||
|
||||
case '1'...'5':
|
||||
case '7'...'9':
|
||||
case '0'...'9':
|
||||
_d("Setting new runlevel %c", rq.runlevel);
|
||||
service_runlevel(rq.runlevel - '0');
|
||||
break;
|
||||
|
||||
case '6':
|
||||
_d("Rebooting system (SIGTERM)");
|
||||
do_shutdown(SHUT_REBOOT);
|
||||
lvl = rq.runlevel - '0';
|
||||
if (lvl == 6)
|
||||
halt = SHUT_REBOOT;
|
||||
service_runlevel(lvl);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
/* Set kernel variables from /etc/sysctl.conf et al
|
||||
*
|
||||
* Copyright (c) 2016 Joachim Nilsson <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <glob.h>
|
||||
#include <lite/lite.h>
|
||||
#include "../plugin.h"
|
||||
|
||||
static void setup(void *UNUSED(arg))
|
||||
{
|
||||
size_t i;
|
||||
glob_t gl;
|
||||
char buf[160];
|
||||
|
||||
glob("/run/sysctl.d/*.conf", 0, NULL, &gl);
|
||||
glob("/etc/sysctl.d/*.conf", GLOB_APPEND, NULL, &gl);
|
||||
glob("/usr/local/lib/sysctl.d/*.conf", GLOB_APPEND, NULL, &gl);
|
||||
glob("/usr/lib/sysctl.d/*.conf", GLOB_APPEND, NULL, &gl);
|
||||
glob("/lib/sysctl.d/*.conf", GLOB_APPEND, NULL, &gl);
|
||||
glob("/mnt/sysctl.d/*.conf", GLOB_APPEND, NULL, &gl);
|
||||
glob("/etc/sysctl.conf", GLOB_APPEND, NULL, &gl);
|
||||
if (gl.gl_pathc > 0) {
|
||||
for (i = 0; i < gl.gl_pathc; i++) {
|
||||
snprintf(buf, sizeof(buf), "/sbin/sysctl -e -p %s >/dev/null", gl.gl_pathv[i]);
|
||||
run(buf);
|
||||
}
|
||||
globfree(&gl);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static plugin_t plugin = {
|
||||
.name = __FILE__,
|
||||
.hook[HOOK_BASEFS_UP] = {
|
||||
.cb = setup
|
||||
},
|
||||
.depends = { "bootmisc", },
|
||||
};
|
||||
|
||||
PLUGIN_INIT(plugin_init)
|
||||
{
|
||||
plugin_register(&plugin);
|
||||
}
|
||||
|
||||
PLUGIN_EXIT(plugin_exit)
|
||||
{
|
||||
plugin_unregister(&plugin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
+8
-29
@@ -27,43 +27,22 @@
|
||||
#include "../helpers.h"
|
||||
#include "../plugin.h"
|
||||
|
||||
/*
|
||||
* No need to clean up files in /etc/resolvconf/run/interface/
|
||||
* this is already taken care of by bootclean
|
||||
*/
|
||||
static void setup(void *UNUSED(arg))
|
||||
{
|
||||
#ifdef USE_ETC_RESOLVCONF_RUN
|
||||
DIR *dir;
|
||||
struct dirent *d;
|
||||
#endif
|
||||
|
||||
_d("Setting up the resolver ...");
|
||||
#ifdef USE_ETC_RESOLVCONF_RUN
|
||||
makepath("/dev/shm/network");
|
||||
makepath("/dev/shm/resolvconf/interface");
|
||||
mkpath("/etc/resolvconf", 0755);
|
||||
mkpath("/etc/resolvconf/run", 0755);
|
||||
mkpath("/var/run/resolvconf", 0755);
|
||||
mkpath("/var/run/resolvconf/interface", 0755);
|
||||
|
||||
if ((dir = opendir("/etc/resolvconf/run/interface")) != NULL) {
|
||||
while ((d = readdir(dir)) != NULL) {
|
||||
if (isalnum(d->d_name[0]))
|
||||
continue;
|
||||
snprintf(line, sizeof(line),
|
||||
"/etc/resolvconf/run/interface/%s", d->d_name);
|
||||
unlink(line);
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_VAR_RUN_RESOLVCONF
|
||||
makepath("/var/run/resolvconf/interface");
|
||||
symlink("../../../etc/resolv.conf", "/var/run/resolvconf/resolv.conf");
|
||||
#endif
|
||||
|
||||
#ifdef USE_ETC_RESOLVCONF_RUN
|
||||
touch("/etc/resolvconf/run/enable-updates");
|
||||
|
||||
chdir("/etc/resolvconf/run/interface");
|
||||
run_parts("/etc/resolvconf/update.d", "-i");
|
||||
chdir("/");
|
||||
#endif /* USE_ETC_RESOLVCONF_RUN */
|
||||
}
|
||||
|
||||
static plugin_t plugin = {
|
||||
|
||||
+2
-2
@@ -71,14 +71,14 @@ static int send_peer(int sd, char *buf, ssize_t len, struct sockaddr *sa, sockle
|
||||
{
|
||||
char *now;
|
||||
|
||||
now = rfctime(buf, &len);
|
||||
now = rfctime(buf, (size_t *)&len);
|
||||
if (!now)
|
||||
return -1; /* On error, close connection. */
|
||||
|
||||
return sendto(sd, now, len, MSG_DONTWAIT, sa, sa_len);
|
||||
}
|
||||
|
||||
static int cb(int type)
|
||||
static int cb(int UNUSED(type))
|
||||
{
|
||||
int sd = STDIN_FILENO;
|
||||
char buf[BUFSIZ];
|
||||
|
||||
@@ -37,6 +37,8 @@ static void setup(void *UNUSED(arg))
|
||||
#endif
|
||||
char line[LINE_SIZE];
|
||||
|
||||
umask(0);
|
||||
|
||||
makedir("/var/run/console", 01777);
|
||||
snprintf(line, sizeof(line), "/var/run/console/%s", username);
|
||||
touch(line);
|
||||
@@ -54,6 +56,8 @@ static void setup(void *UNUSED(arg))
|
||||
|
||||
if (fexist("/sbin/restorecon"))
|
||||
run("/sbin/restorecon /tmp/.ICE-unix /tmp/.X11-unix");
|
||||
|
||||
umask(022);
|
||||
}
|
||||
|
||||
static plugin_t plugin = {
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/reboot.h>
|
||||
#include "util.h"
|
||||
|
||||
#ifndef RB_SW_SUSPEND /* Since Linux 2.5.18, but not in GLIBC until 2.19 */
|
||||
#define RB_SW_SUSPEND 0xd000fce2
|
||||
@@ -43,16 +44,15 @@ typedef enum {
|
||||
|
||||
static cmd_t cmd = CMD_UNKNOWN;
|
||||
static char *msg = NULL;
|
||||
extern char *__progname;
|
||||
|
||||
static void translate(void)
|
||||
{
|
||||
if (cmd == CMD_UNKNOWN) {
|
||||
if (!strcmp(__progname, "halt") || !strcmp(__progname, "shutdown"))
|
||||
if (!strcmp(prognm, "halt") || !strcmp(prognm, "shutdown"))
|
||||
cmd = CMD_HALT;
|
||||
else if (!strcmp(__progname, "poweroff"))
|
||||
else if (!strcmp(prognm, "poweroff"))
|
||||
cmd = CMD_POWEROFF;
|
||||
else if (!strcmp(__progname, "suspend"))
|
||||
else if (!strcmp(prognm, "suspend"))
|
||||
cmd = CMD_SUSPEND;
|
||||
else
|
||||
cmd = CMD_REBOOT;
|
||||
@@ -91,7 +91,7 @@ static int usage(int rc)
|
||||
" --halt Halt system, regardless of how the command is called.\n"
|
||||
" -p, --poweroff Power-off system, regardless of how the command is called.\n"
|
||||
" --reboot Reboot system, regardless of how the command is called.\n"
|
||||
"\n", __progname, msg);
|
||||
"\n", prognm, msg);
|
||||
|
||||
return rc;
|
||||
}
|
||||
@@ -109,6 +109,7 @@ int main(int argc, char *argv[])
|
||||
};
|
||||
|
||||
/* Initial command taken from program name */
|
||||
progname(argv[0]);
|
||||
translate();
|
||||
|
||||
while ((c = getopt_long(argc, argv, "h?fHpr", long_options, NULL)) != EOF) {
|
||||
@@ -191,6 +192,8 @@ int main(int argc, char *argv[])
|
||||
|
||||
if (c)
|
||||
err(1, "Failed signalling init to %s", msg);
|
||||
else
|
||||
sleep(2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -24,6 +24,8 @@
|
||||
|
||||
#include "config.h" /* Generated by configure script */
|
||||
|
||||
#include <ctype.h> /* isblank() */
|
||||
#include <sched.h>
|
||||
#include <string.h>
|
||||
#include <sys/wait.h>
|
||||
#include <net/if.h>
|
||||
@@ -41,11 +43,8 @@
|
||||
#include "tty.h"
|
||||
#include "utmp-api.h"
|
||||
|
||||
#define RESPAWN_MAX 10 /* Prevent endless respawn of faulty services. */
|
||||
#define RESPAWN_MAX 10 /* Prevent endless respawn of faulty services. */
|
||||
|
||||
#ifndef INETD_DISABLED
|
||||
static svc_t *find_inetd_svc (char *path, char *service, char *proto);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* service_enabled - Should the service run?
|
||||
@@ -72,16 +71,17 @@ int service_enabled(svc_t *svc)
|
||||
|
||||
/**
|
||||
* service_timeout_cb - libuev callback wrapper for service timeouts
|
||||
* @w: Watcher
|
||||
* @arg: Callback argument, from init
|
||||
* @events: Error, or ready to read/write (N/A for relative timers)
|
||||
*
|
||||
* Calls the callback registered with the call to
|
||||
* service_timeout_after().
|
||||
*/
|
||||
static void service_timeout_cb(uev_t *w, void *_svc, int events)
|
||||
static void service_timeout_cb(uev_t *UNUSED(w), void *arg, int UNUSED(events))
|
||||
{
|
||||
svc_t *svc = _svc;
|
||||
svc_t *svc = arg;
|
||||
|
||||
(void)(w);
|
||||
(void)(events);
|
||||
svc->timer_cb(svc);
|
||||
}
|
||||
|
||||
@@ -96,15 +96,13 @@ static void service_timeout_cb(uev_t *w, void *_svc, int events)
|
||||
*
|
||||
* @return 0 on success, non-zero on error.
|
||||
*/
|
||||
static int service_timeout_after(svc_t *svc, int timeout,
|
||||
void (*cb)(svc_t *svc))
|
||||
static int service_timeout_after(svc_t *svc, int timeout, void (*cb)(svc_t *svc))
|
||||
{
|
||||
if (svc->timer_cb)
|
||||
return -EBUSY;
|
||||
|
||||
svc->timer_cb = cb;
|
||||
return uev_timer_init(ctx, &svc->timer, service_timeout_cb,
|
||||
svc, timeout, 0);
|
||||
return uev_timer_init(ctx, &svc->timer, service_timeout_cb, svc, timeout, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -124,26 +122,10 @@ static int service_timeout_cancel(svc_t *svc)
|
||||
|
||||
err = uev_timer_stop(&svc->timer);
|
||||
svc->timer_cb = NULL;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* service_stop_is_done - Have all stopped services been collected?
|
||||
*
|
||||
* Returns:
|
||||
* 1, if all stopped services have been collected. 0 otherwise.
|
||||
*/
|
||||
int service_stop_is_done(void)
|
||||
{
|
||||
svc_t *svc;
|
||||
|
||||
for (svc = svc_iterator(1); svc; svc = svc_iterator(0))
|
||||
if (svc->state == SVC_STOPPING_STATE)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int is_norespawn(void)
|
||||
{
|
||||
return sig_stopped() ||
|
||||
@@ -204,7 +186,7 @@ static int service_start(svc_t *svc)
|
||||
/* Declare we're waiting for svc to create its pidfile */
|
||||
svc_starting(svc);
|
||||
|
||||
/* Block sigchild while forking. */
|
||||
/* Block SIGCHLD while forking. */
|
||||
sigemptyset(&nmask);
|
||||
sigaddset(&nmask, SIGCHLD);
|
||||
sigprocmask(SIG_BLOCK, &nmask, &omask);
|
||||
@@ -486,6 +468,20 @@ void service_reload_dynamic(void)
|
||||
*/
|
||||
void service_runlevel(int newlevel)
|
||||
{
|
||||
if (newlevel == 0 || newlevel == 6) {
|
||||
/* If we enabled terse mode at boot, restore to previous setting at shutdown */
|
||||
if (quiet) {
|
||||
silent = SILENT_MODE;
|
||||
if (!silent) {
|
||||
sched_yield();
|
||||
fputs("\n", stderr);
|
||||
}
|
||||
}
|
||||
|
||||
/* Call all shutdown hooks before rebooting... */
|
||||
plugin_run_hooks(HOOK_SHUTDOWN);
|
||||
}
|
||||
|
||||
sm_set_runlevel(&sm, newlevel);
|
||||
sm_step(&sm);
|
||||
}
|
||||
@@ -564,6 +560,9 @@ int service_register(int type, char *line, time_t mtime, char *username)
|
||||
if (desc) {
|
||||
*desc = 0;
|
||||
desc += 3;
|
||||
|
||||
while (*desc && isblank(*desc))
|
||||
desc++;
|
||||
}
|
||||
|
||||
cmd = strtok(line, " ");
|
||||
@@ -634,7 +633,7 @@ int service_register(int type, char *line, time_t mtime, char *username)
|
||||
}
|
||||
|
||||
/* Check if known inetd, then add ifnames for filtering only. */
|
||||
svc = find_inetd_svc(cmd, service, proto);
|
||||
svc = inetd_find_svc(cmd, service, proto);
|
||||
if (svc)
|
||||
goto inetd_setup;
|
||||
|
||||
@@ -701,7 +700,7 @@ recreate:
|
||||
name = plugin->name;
|
||||
|
||||
if (inetd_new(&svc->inetd, name, service, proto, forking, svc)) {
|
||||
_e("Failed registering new inetd service %s", service);
|
||||
_e("Failed registering new inetd service %s/%s", service, proto);
|
||||
return svc_del(svc);
|
||||
}
|
||||
|
||||
@@ -724,6 +723,7 @@ recreate:
|
||||
|
||||
/* New, recently modified or unchanged ... used on reload. */
|
||||
svc_check_dirty(svc, mtime);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -772,8 +772,9 @@ void service_monitor(pid_t lost)
|
||||
|
||||
static void service_retry(svc_t *svc)
|
||||
{
|
||||
int *restart_counter = (int *)&svc->restart_counter;
|
||||
int timeout;
|
||||
int *restart_counter = (int *)&svc->restart_counter;
|
||||
|
||||
service_timeout_cancel(svc);
|
||||
|
||||
if (svc->state != SVC_HALTED_STATE ||
|
||||
@@ -785,7 +786,7 @@ static void service_retry(svc_t *svc)
|
||||
|
||||
if (*restart_counter >= RESPAWN_MAX) {
|
||||
_e("%s keeps crashing, not restarting", svc->desc);
|
||||
svc->block = SVC_BLOCK_CRASHING;
|
||||
svc_crashing(svc);
|
||||
*restart_counter = 0;
|
||||
service_step(svc);
|
||||
return;
|
||||
@@ -793,16 +794,13 @@ static void service_retry(svc_t *svc)
|
||||
|
||||
(*restart_counter)++;
|
||||
|
||||
_d("%s crashed, trying to start it again, attempt %d",
|
||||
svc->desc, *restart_counter);
|
||||
|
||||
svc->block = SVC_BLOCK_NONE;
|
||||
_d("%s crashed, trying to start it again, attempt %d", svc->desc, *restart_counter);
|
||||
svc_unblock(svc);
|
||||
service_step(svc);
|
||||
|
||||
/* Wait 2s for the first 5 respawns, then back off to 5s */
|
||||
timeout = ((*restart_counter) <= (RESPAWN_MAX / 2)) ? 2000 : 5000;
|
||||
service_timeout_after(svc, timeout, service_retry);
|
||||
return;
|
||||
}
|
||||
|
||||
static void svc_set_state(svc_t *svc, svc_state_t new)
|
||||
@@ -820,14 +818,11 @@ static void svc_set_state(svc_t *svc, svc_state_t new)
|
||||
|
||||
void service_step(svc_t *svc)
|
||||
{
|
||||
/* These fields are marked as const in svc_t, only this
|
||||
* function is allowed to modify them */
|
||||
int err;
|
||||
int *restart_counter = (int *)&svc->restart_counter;
|
||||
|
||||
svc_cmd_t enabled;
|
||||
svc_state_t old_state;
|
||||
cond_state_t cond;
|
||||
int err;
|
||||
|
||||
restart:
|
||||
old_state = svc->state;
|
||||
@@ -837,7 +832,7 @@ restart:
|
||||
svc_status(svc), enabled ? "en" : "dis", svc_dirtystr(svc),
|
||||
condstr(cond_get_agg(svc->cond)));
|
||||
|
||||
switch(svc->state) {
|
||||
switch (svc->state) {
|
||||
case SVC_HALTED_STATE:
|
||||
if (enabled)
|
||||
svc_set_state(svc, SVC_READY_STATE);
|
||||
@@ -846,7 +841,7 @@ restart:
|
||||
case SVC_DONE_STATE:
|
||||
#ifndef INETD_DISABLED
|
||||
if (svc_is_inetd_conn(svc)) {
|
||||
if (svc_is_busy(svc)) {
|
||||
if (svc_is_busy(svc->inetd.svc)) {
|
||||
svc_unblock(svc->inetd.svc);
|
||||
service_step(svc->inetd.svc);
|
||||
}
|
||||
@@ -899,23 +894,7 @@ restart:
|
||||
}
|
||||
|
||||
svc_mark_clean(svc);
|
||||
|
||||
switch (svc->type) {
|
||||
case SVC_TYPE_INETD:
|
||||
case SVC_TYPE_SERVICE:
|
||||
svc_set_state(svc, SVC_RUNNING_STATE);
|
||||
break;
|
||||
|
||||
case SVC_TYPE_INETD_CONN:
|
||||
case SVC_TYPE_TASK:
|
||||
case SVC_TYPE_RUN:
|
||||
svc_set_state(svc, SVC_STOPPING_STATE);
|
||||
break;
|
||||
|
||||
default:
|
||||
_e("unknown service type %d", svc->type);
|
||||
break;
|
||||
}
|
||||
svc_set_state(svc, SVC_RUNNING_STATE);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -926,15 +905,25 @@ restart:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!svc->pid && !svc_is_inetd(svc)) {
|
||||
svc->block = SVC_BLOCK_RESTARTING;
|
||||
svc_set_state(svc, SVC_HALTED_STATE);
|
||||
if (!svc->pid) {
|
||||
if (svc_is_daemon(svc)) {
|
||||
svc_restarting(svc);
|
||||
svc_set_state(svc, SVC_HALTED_STATE);
|
||||
|
||||
/* Restart directly after the first crash,
|
||||
* then retry after 2s. */
|
||||
_d("delayed restart of %s", svc->desc);
|
||||
service_timeout_after(svc, 1, service_retry);
|
||||
break;
|
||||
/*
|
||||
* Restart directly after the first crash,
|
||||
* then retry after 2 sec
|
||||
*/
|
||||
_d("delayed restart of %s", svc->desc);
|
||||
service_timeout_after(svc, 1, service_retry);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Collected inetd connection, drive it to stopping */
|
||||
if (svc_is_inetd_conn(svc)) {
|
||||
svc_set_state(svc, SVC_STOPPING_STATE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
cond = cond_get_agg(svc->cond);
|
||||
@@ -1007,35 +996,9 @@ restart:
|
||||
|
||||
void service_step_all(int types)
|
||||
{
|
||||
svc_t *svc;
|
||||
|
||||
for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) {
|
||||
if (!(svc->type & types))
|
||||
continue;
|
||||
|
||||
service_step(svc);
|
||||
}
|
||||
svc_foreach_type(types, service_step);
|
||||
}
|
||||
|
||||
#ifndef INETD_DISABLED
|
||||
static svc_t *find_inetd_svc(char *path, char *service, char *proto)
|
||||
{
|
||||
svc_t *svc;
|
||||
|
||||
for (svc = svc_inetd_iterator(1); svc; svc = svc_inetd_iterator(0)) {
|
||||
if (strncmp(path, svc->cmd, strlen(svc->cmd)))
|
||||
continue;
|
||||
|
||||
if (inetd_match(&svc->inetd, service, proto)) {
|
||||
_d("Found a matching inetd svc for %s %s %s", path, service, proto);
|
||||
return svc;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* indent-tabs-mode: t
|
||||
|
||||
@@ -34,10 +34,8 @@ int service_enabled (svc_t *svc);
|
||||
|
||||
void service_reload_dynamic (void);
|
||||
|
||||
void service_step(svc_t *svc);
|
||||
void service_step_all(int types);
|
||||
|
||||
int service_stop_is_done(void);
|
||||
void service_step (svc_t *svc);
|
||||
void service_step_all (int types);
|
||||
|
||||
#endif /* FINIT_SERVICE_H_ */
|
||||
|
||||
|
||||
@@ -64,7 +64,7 @@
|
||||
* Finit currently forwards this to SIGUSR2.
|
||||
*/
|
||||
|
||||
#include <sched.h>
|
||||
#include <dirent.h>
|
||||
#include <string.h> /* strerror() */
|
||||
#include <sys/reboot.h>
|
||||
#include <sys/wait.h>
|
||||
@@ -80,16 +80,64 @@
|
||||
#include "service.h"
|
||||
#include "utmp-api.h"
|
||||
|
||||
/*
|
||||
* Old-style SysV shutdown sends a setenv cmd INIT_HALT with "=HALT",
|
||||
* "=POWERDOWN", or "" to cancel shutdown, before requesting change to
|
||||
* runlevel 6 over the /dev/initctl FIFO. See plugins/initctl.c
|
||||
*/
|
||||
shutop_t halt = SHUT_DEFAULT;
|
||||
|
||||
static int stopped = 0;
|
||||
static uev_t sigterm_watcher, sigusr1_watcher, sigusr2_watcher;
|
||||
static uev_t sighup_watcher, sigint_watcher, sigpwr_watcher;
|
||||
static uev_t sigchld_watcher, sigsegv_watcher;
|
||||
static uev_t sigchld_watcher;
|
||||
static uev_t sigstop_watcher, sigtstp_watcher, sigcont_watcher;
|
||||
|
||||
void mdadm_wait(void);
|
||||
void unmount_tmpfs(void);
|
||||
void unmount_regular(void);
|
||||
|
||||
/*
|
||||
* Kernel threads have no cmdline so fgets() returns NULL for them. We
|
||||
* also skip "special" processes, e.g. mdadm/mdmon or watchdogd that must
|
||||
* not be stopped here, for various reasons.
|
||||
*
|
||||
* https://www.freedesktop.org/wiki/Software/systemd/RootStorageDaemons/
|
||||
*/
|
||||
void do_kill(int signo)
|
||||
{
|
||||
DIR *dirp;
|
||||
|
||||
dirp = opendir("/proc");
|
||||
if (dirp) {
|
||||
struct dirent *d;
|
||||
|
||||
while ((d = readdir(dirp))) {
|
||||
int pid;
|
||||
FILE *fp;
|
||||
char file[80] = "";
|
||||
|
||||
if (d->d_type != DT_DIR)
|
||||
continue;
|
||||
|
||||
pid = atoi(d->d_name);
|
||||
if (!pid)
|
||||
continue;
|
||||
|
||||
snprintf(file, sizeof(file), "/proc/%s/cmdline", d->d_name);
|
||||
fp = fopen(file, "r");
|
||||
if (!fp)
|
||||
continue;
|
||||
|
||||
if (fgets(file, sizeof(file), fp)) {
|
||||
if (file[0] != '@')
|
||||
kill(pid, signo);
|
||||
}
|
||||
fclose(fp);
|
||||
}
|
||||
closedir(dirp);
|
||||
}
|
||||
}
|
||||
|
||||
void do_shutdown(shutop_t op)
|
||||
{
|
||||
@@ -98,30 +146,16 @@ void do_shutdown(shutop_t op)
|
||||
if (sdown)
|
||||
run_interactive(sdown, "Calling shutdown hook: %s", sdown);
|
||||
|
||||
/* If we enabled terse mode at boot, restore to previous setting at shutdown */
|
||||
if (quiet) {
|
||||
silent = SILENT_MODE;
|
||||
if (!silent) {
|
||||
sched_yield();
|
||||
fputs("\n", stderr);
|
||||
}
|
||||
}
|
||||
|
||||
/* Call all shutdown hooks before rebooting... */
|
||||
plugin_run_hooks(HOOK_SHUTDOWN);
|
||||
|
||||
/* Update UTMP db */
|
||||
utmp_set_halt();
|
||||
|
||||
/* Here is where we signal watchdogd to do a forced reset for us */
|
||||
_d("Sending SIGTERM to all processes");
|
||||
kill(-1, SIGTERM);
|
||||
|
||||
/* Wait for WDT to timeout, should be no more than ~1 sec. */
|
||||
/*
|
||||
* Tell all remaining non-monitored processes to exit, give them
|
||||
* some time to exit gracefully, 2 sec is customary.
|
||||
*/
|
||||
do_kill(SIGTERM);
|
||||
do_sleep(2);
|
||||
|
||||
_d("Sending SIGKILL to remaining processes");
|
||||
kill(-1, SIGKILL);
|
||||
do_kill(SIGKILL);
|
||||
|
||||
/* Exit plugins and API gracefully */
|
||||
plugin_exit();
|
||||
@@ -152,6 +186,7 @@ void do_shutdown(shutop_t op)
|
||||
unmount_regular();
|
||||
|
||||
/* We sit on / so we must remount it ro, try all the things! */
|
||||
sync();
|
||||
run("/bin/mount -n -o remount,ro -t dummytype dummydev /");
|
||||
run("/bin/mount -n -o remount,ro dummydev /");
|
||||
run("/bin/mount -n -o remount,ro /");
|
||||
@@ -159,6 +194,15 @@ void do_shutdown(shutop_t op)
|
||||
/* Call mdadm to mark any RAID array(s) as clean before halting. */
|
||||
mdadm_wait();
|
||||
|
||||
/* Wait here until the WDT reboots, or timeout */
|
||||
if (wdogpid) {
|
||||
int timeout = 10;
|
||||
|
||||
print(kill(wdogpid, SIGPWR) == 1, "Pending watchdog reboot");
|
||||
while (timeout--)
|
||||
do_sleep(1);
|
||||
}
|
||||
|
||||
_d("%s", op == SHUT_REBOOT ? "Rebooting" : "Halting");
|
||||
if (op == SHUT_REBOOT)
|
||||
reboot(RB_AUTOBOOT);
|
||||
@@ -175,6 +219,7 @@ void do_shutdown(shutop_t op)
|
||||
*/
|
||||
static void sighup_cb(uev_t *UNUSED(w), void *UNUSED(arg), int UNUSED(events))
|
||||
{
|
||||
_d("...");
|
||||
/* INIT_CMD_RELOAD: 'init q', 'initctl reload', and SIGHUP */
|
||||
service_reload_dynamic();
|
||||
}
|
||||
@@ -184,7 +229,9 @@ static void sighup_cb(uev_t *UNUSED(w), void *UNUSED(arg), int UNUSED(events))
|
||||
*/
|
||||
static void sigint_cb(uev_t *UNUSED(w), void *UNUSED(arg), int UNUSED(events))
|
||||
{
|
||||
do_shutdown(SHUT_REBOOT);
|
||||
_d("...");
|
||||
halt = SHUT_REBOOT;
|
||||
service_runlevel(6);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -192,7 +239,9 @@ static void sigint_cb(uev_t *UNUSED(w), void *UNUSED(arg), int UNUSED(events))
|
||||
*/
|
||||
static void sigusr1_cb(uev_t *UNUSED(w), void *UNUSED(arg), int UNUSED(events))
|
||||
{
|
||||
do_shutdown(SHUT_HALT);
|
||||
_d("...");
|
||||
halt = SHUT_HALT;
|
||||
service_runlevel(0);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -200,7 +249,9 @@ static void sigusr1_cb(uev_t *UNUSED(w), void *UNUSED(arg), int UNUSED(events))
|
||||
*/
|
||||
static void sigusr2_cb(uev_t *UNUSED(w), void *UNUSED(arg), int UNUSED(events))
|
||||
{
|
||||
do_shutdown(SHUT_OFF);
|
||||
_d("...");
|
||||
halt = SHUT_OFF;
|
||||
service_runlevel(0);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -208,7 +259,9 @@ static void sigusr2_cb(uev_t *UNUSED(w), void *UNUSED(arg), int UNUSED(events))
|
||||
*/
|
||||
static void sigterm_cb(uev_t *UNUSED(w), void *UNUSED(arg), int UNUSED(events))
|
||||
{
|
||||
do_shutdown(SHUT_REBOOT);
|
||||
_d("...");
|
||||
halt = SHUT_REBOOT;
|
||||
service_runlevel(6);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -228,15 +281,6 @@ static void sigchld_cb(uev_t *UNUSED(w), void *UNUSED(arg), int UNUSED(events))
|
||||
} while (pid > 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* SIGSEGV: mostly if service callbacks segfault
|
||||
*/
|
||||
static void sigsegv_cb(uev_t *UNUSED(w), void *UNUSED(arg), int UNUSED(events))
|
||||
{
|
||||
_e("PID %d caused a segfault!\n", getpid());
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
/*
|
||||
* SIGSTOP/SIGTSTP: Paused by user or netflash
|
||||
*/
|
||||
@@ -340,9 +384,6 @@ void sig_setup(uev_ctx_t *ctx)
|
||||
/* After initial bootstrap of Finit we call the service monitor to reap children */
|
||||
uev_signal_init(ctx, &sigchld_watcher, sigchld_cb, NULL, SIGCHLD);
|
||||
|
||||
/* Trap SIGSEGV in case service callbacks crash */
|
||||
uev_signal_init(ctx, &sigsegv_watcher, sigsegv_cb, NULL, SIGSEGV);
|
||||
|
||||
/* Stopping init is a bit tricky. */
|
||||
uev_signal_init(ctx, &sigstop_watcher, sigstop_cb, NULL, SIGSTOP);
|
||||
uev_signal_init(ctx, &sigtstp_watcher, sigstop_cb, NULL, SIGTSTP);
|
||||
|
||||
@@ -66,6 +66,8 @@ typedef enum {
|
||||
SHUT_REBOOT
|
||||
} shutop_t;
|
||||
|
||||
extern shutop_t halt;
|
||||
|
||||
void do_shutdown (shutop_t op);
|
||||
int sig_stopped (void);
|
||||
void sig_init (void);
|
||||
|
||||
@@ -127,6 +127,12 @@ restart:
|
||||
_d("Setting new runlevel --> %d <-- previous %d", runlevel, prevlevel);
|
||||
runlevel_set(prevlevel, runlevel);
|
||||
|
||||
/* Disable login in single-user mode as well as shutdown/reboot */
|
||||
if (runlevel == 1 || runlevel == 0 || runlevel == 6)
|
||||
touch("/etc/nologin");
|
||||
else
|
||||
erase("/etc/nologin");
|
||||
|
||||
/* Make sure to (re)load all *.conf in /etc/finit.d/ */
|
||||
conf_reload_dynamic();
|
||||
|
||||
@@ -140,7 +146,7 @@ restart:
|
||||
case SM_RUNLEVEL_WAIT_STATE:
|
||||
/* Need to wait for any services to stop? If so, exit early
|
||||
* and perform second stage from service_monitor later. */
|
||||
if (!service_stop_is_done())
|
||||
if (!svc_stop_completed())
|
||||
break;
|
||||
|
||||
/* Prev runlevel services stopped, call hooks before starting new runlevel ... */
|
||||
@@ -154,19 +160,14 @@ restart:
|
||||
/* Cleanup stale services */
|
||||
svc_clean_dynamic(service_unregister);
|
||||
|
||||
/* Disable login in single-user mode as well as shutdown/reboot */
|
||||
if (runlevel == 1 || runlevel == 0 || runlevel == 6)
|
||||
touch("/etc/nologin");
|
||||
else
|
||||
erase("/etc/nologin");
|
||||
|
||||
if (0 == runlevel) {
|
||||
do_shutdown(SHUT_OFF);
|
||||
sm->state = SM_RUNNING_STATE;
|
||||
break;
|
||||
}
|
||||
if (6 == runlevel) {
|
||||
do_shutdown(SHUT_REBOOT);
|
||||
/*
|
||||
* "I've seen things you people wouldn't believe. Attack ships on fire off
|
||||
* the shoulder of Orion. I watched C-beams glitter in the dark near the
|
||||
* Tannhäuser Gate. All those .. moments .. will be lost in time, like
|
||||
* tears ... in ... rain."
|
||||
*/
|
||||
if (runlevel == 0 || runlevel == 6) {
|
||||
do_shutdown(halt);
|
||||
sm->state = SM_RUNNING_STATE;
|
||||
break;
|
||||
}
|
||||
@@ -195,7 +196,7 @@ restart:
|
||||
case SM_RELOAD_WAIT_STATE:
|
||||
/* Need to wait for any services to stop? If so, exit early
|
||||
* and perform second stage from service_monitor later. */
|
||||
if (!service_stop_is_done())
|
||||
if (!svc_stop_completed())
|
||||
break;
|
||||
|
||||
sm->in_teardown = 0;
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <strings.h>
|
||||
#include <lite/lite.h>
|
||||
|
||||
#include "finit.h"
|
||||
#include "svc.h"
|
||||
@@ -261,6 +260,44 @@ void svc_foreach_dynamic(void (*cb)(svc_t *))
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* svc_foreach_type - Run a callback for each matching type
|
||||
* @types: Mask of service types
|
||||
* @cb: Callback to run for each matching type
|
||||
*/
|
||||
void svc_foreach_type(int types, void (*cb)(svc_t *))
|
||||
{
|
||||
svc_t *svc;
|
||||
|
||||
if (!cb)
|
||||
return;
|
||||
|
||||
for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) {
|
||||
if (!(svc->type & types))
|
||||
continue;
|
||||
|
||||
cb(svc);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* svc_stop_completed - Have all stopped services been collected?
|
||||
*
|
||||
* Returns:
|
||||
* 1, if all stopped services have been collected. 0 otherwise.
|
||||
*/
|
||||
int svc_stop_completed(void)
|
||||
{
|
||||
svc_t *svc;
|
||||
|
||||
for (svc = svc_iterator(1); svc; svc = svc_iterator(0))
|
||||
if (svc->state == SVC_STOPPING_STATE)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* svc_find - Find a service object by its full path name
|
||||
* @cmd: Full path name, e.g., /sbin/syslogd
|
||||
@@ -441,7 +478,7 @@ char *svc_status(svc_t *svc)
|
||||
case SVC_BLOCK_USER:
|
||||
return "blocked";
|
||||
|
||||
case SVC_BLOCK_INETD_BUSY:
|
||||
case SVC_BLOCK_BUSY:
|
||||
return "busy";
|
||||
|
||||
case SVC_BLOCK_RESTARTING:
|
||||
|
||||
@@ -60,7 +60,7 @@ typedef enum {
|
||||
SVC_BLOCK_MISSING,
|
||||
SVC_BLOCK_CRASHING,
|
||||
SVC_BLOCK_USER,
|
||||
SVC_BLOCK_INETD_BUSY,
|
||||
SVC_BLOCK_BUSY,
|
||||
SVC_BLOCK_RESTARTING,
|
||||
} svc_block_t;
|
||||
|
||||
@@ -114,8 +114,10 @@ typedef struct svc {
|
||||
char args[MAX_NUM_SVC_ARGS][MAX_ARG_LEN];
|
||||
char desc[MAX_STR_LEN];
|
||||
|
||||
/* Used to forcefully kill services that won't shutdown on
|
||||
* termination and to delay restarts of crashing services. */
|
||||
/*
|
||||
* Used to forcefully kill services that won't shutdown on
|
||||
* termination and to delay restarts of crashing services.
|
||||
*/
|
||||
uev_t timer;
|
||||
void (*timer_cb)(struct svc *svc);
|
||||
} svc_t;
|
||||
@@ -153,6 +155,9 @@ svc_t *svc_job_iterator (int first, int job);
|
||||
|
||||
void svc_foreach (void (*cb)(svc_t *));
|
||||
void svc_foreach_dynamic (void (*cb)(svc_t *));
|
||||
void svc_foreach_type (int types, void (*cb)(svc_t *));
|
||||
|
||||
int svc_stop_completed (void);
|
||||
|
||||
void svc_mark_dynamic (void);
|
||||
void svc_check_dirty (svc_t *svc, time_t mtime);
|
||||
@@ -183,11 +188,12 @@ static inline int svc_is_inetd_conn(svc_t *svc) { return svc && SVC_TYPE_INETD_C
|
||||
static inline int svc_is_daemon (svc_t *svc) { return svc && SVC_TYPE_SERVICE == svc->type; }
|
||||
|
||||
static inline int svc_is_blocked (svc_t *svc) { return svc->block != SVC_BLOCK_NONE; }
|
||||
static inline int svc_is_busy (svc_t *svc) { return svc->block == SVC_BLOCK_INETD_BUSY; }
|
||||
static inline int svc_is_busy (svc_t *svc) { return svc->block == SVC_BLOCK_BUSY; }
|
||||
static inline void svc_unblock (svc_t *svc) { svc->block = SVC_BLOCK_NONE; }
|
||||
static inline void svc_block (svc_t *svc) { svc->block = SVC_BLOCK_USER; }
|
||||
static inline void svc_busy (svc_t *svc) { svc->block = SVC_BLOCK_INETD_BUSY; }
|
||||
static inline void svc_busy (svc_t *svc) { svc->block = SVC_BLOCK_BUSY; }
|
||||
static inline void svc_missing (svc_t *svc) { svc->block = SVC_BLOCK_MISSING; }
|
||||
static inline void svc_restarting (svc_t *svc) { svc->block = SVC_BLOCK_RESTARTING; }
|
||||
static inline void svc_crashing (svc_t *svc) { svc->block = SVC_BLOCK_CRASHING; }
|
||||
|
||||
#endif /* FINIT_SVC_H_ */
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
*/
|
||||
|
||||
#include <signal.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <lite/lite.h>
|
||||
|
||||
@@ -33,7 +35,10 @@
|
||||
#include "tty.h"
|
||||
#include "utmp-api.h"
|
||||
|
||||
LIST_HEAD(, tty_node) tty_list = LIST_HEAD_INITIALIZER();
|
||||
#ifdef FALLBACK_SHELL
|
||||
static pid_t fallback = 0;
|
||||
#endif
|
||||
static LIST_HEAD(, tty_node) tty_list = LIST_HEAD_INITIALIZER();
|
||||
|
||||
|
||||
/* tty [!1-9,S] <DEV> [BAUD[,BAUD,...]] [TERM] */
|
||||
@@ -118,6 +123,19 @@ size_t tty_num(void)
|
||||
return num;
|
||||
}
|
||||
|
||||
size_t tty_num_active(void)
|
||||
{
|
||||
size_t num = 0;
|
||||
tty_node_t *entry;
|
||||
|
||||
LIST_FOREACH(entry, &tty_list, link) {
|
||||
if (entry->data.pid)
|
||||
num++;
|
||||
}
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
tty_node_t *tty_find_by_pid(pid_t pid)
|
||||
{
|
||||
tty_node_t *entry;
|
||||
@@ -195,13 +213,56 @@ int tty_enabled(finit_tty_t *tty, int runlevel)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* TTY monitor, called by service_monitor() */
|
||||
/*
|
||||
* Fallback shell if no TTYs are active
|
||||
*/
|
||||
int tty_fallback(pid_t lost)
|
||||
{
|
||||
#ifdef FALLBACK_SHELL
|
||||
if (lost == 1) {
|
||||
if (fallback) {
|
||||
_d("Stopping fallback shell");
|
||||
kill(fallback, SIGKILL);
|
||||
fallback = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (fallback != lost || tty_num_active()) {
|
||||
_d("Not starting fallback (%d) shell, lost pid %d", fallback, lost);
|
||||
return 0;
|
||||
}
|
||||
|
||||
_d("Starting fallback shell");
|
||||
fallback = fork();
|
||||
if (fallback)
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* Become session leader and set controlling TTY
|
||||
* to enable Ctrl-C and job control in shell.
|
||||
*/
|
||||
setsid();
|
||||
ioctl(STDIN_FILENO, TIOCSCTTY, 1);
|
||||
|
||||
_exit(execl(_PATH_BSHELL, _PATH_BSHELL, NULL));
|
||||
#else
|
||||
(void)lost;
|
||||
#endif /* FALLBACK_SHELL */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* TTY monitor, called by service_monitor()
|
||||
*/
|
||||
int tty_respawn(pid_t pid)
|
||||
{
|
||||
tty_node_t *entry = tty_find_by_pid(pid);
|
||||
|
||||
if (!entry)
|
||||
return 0;
|
||||
return tty_fallback(pid);
|
||||
|
||||
/* Set DEAD_PROCESS UTMP entry */
|
||||
utmp_set_dead(pid);
|
||||
@@ -228,6 +289,9 @@ void tty_runlevel(int runlevel)
|
||||
else
|
||||
tty_start(&entry->data);
|
||||
}
|
||||
|
||||
/* Start fallback shell if enabled && no TTYs */
|
||||
tty_fallback(tty_num_active() > 0 ? 1 : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -49,6 +49,7 @@ typedef struct tty_node {
|
||||
int tty_register (char *line);
|
||||
tty_node_t *tty_find (char *dev);
|
||||
size_t tty_num (void);
|
||||
size_t tty_num_active (void);
|
||||
tty_node_t *tty_find_by_pid (pid_t pid);
|
||||
void tty_start (finit_tty_t *tty);
|
||||
void tty_stop (finit_tty_t *tty);
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
/* Misc. shared utility functions for initctl, reboot and finit
|
||||
*
|
||||
* Copyright (c) 2016 Joachim Nilsson <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
char *prognm = NULL;
|
||||
|
||||
char *progname(char *arg0)
|
||||
{
|
||||
prognm = strrchr(arg0, '/');
|
||||
if (prognm)
|
||||
prognm++;
|
||||
else
|
||||
prognm = arg0;
|
||||
|
||||
return prognm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
@@ -0,0 +1,38 @@
|
||||
/* Misc. shared utility functions for initctl, reboot and finit
|
||||
*
|
||||
* Copyright (c) 2016 Joachim Nilsson <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef FINIT_UTIL_H_
|
||||
#define FINIT_UTIL_H_
|
||||
|
||||
extern char *prognm;
|
||||
|
||||
char *progname(char *arg0);
|
||||
|
||||
#endif /* FINIT_UTIL_H_ */
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
@@ -21,6 +21,9 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef FINIT_UTMP_API_H_
|
||||
#define FINIT_UTMP_API_H_
|
||||
|
||||
int utmp_set (int type, int pid, char *line, char *id, char *user);
|
||||
int utmp_set_boot (void);
|
||||
int utmp_set_halt (void);
|
||||
@@ -30,6 +33,8 @@ int utmp_set_dead (int pid);
|
||||
int utmp_set_runlevel(int pre, int now);
|
||||
int utmp_show (char *file);
|
||||
|
||||
#endif /* FINIT_UTMP_API_H_ */
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* indent-tabs-mode: t
|
||||
|
||||
+135
@@ -0,0 +1,135 @@
|
||||
/* Built-in watchdog daemon
|
||||
*
|
||||
* Copyright (c) 2016 Joachim Nilsson <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <paths.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <linux/watchdog.h>
|
||||
|
||||
#include "finit.h"
|
||||
#include "helpers.h"
|
||||
#include "watchdog.h"
|
||||
|
||||
int running = 1;
|
||||
int handover = 0;
|
||||
|
||||
static int notify(void)
|
||||
{
|
||||
int sd, result = 255;
|
||||
ssize_t len;
|
||||
struct sockaddr_un sun = {
|
||||
.sun_family = AF_UNIX,
|
||||
.sun_path = INIT_SOCKET,
|
||||
};
|
||||
struct init_request rq;
|
||||
|
||||
sd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (-1 == sd)
|
||||
return -1;
|
||||
|
||||
if (connect(sd, (struct sockaddr*)&sun, sizeof(sun)) == -1)
|
||||
goto exit;
|
||||
|
||||
rq.cmd = INIT_CMD_WDOG_HELLO;
|
||||
rq.magic = INIT_MAGIC;
|
||||
rq.runlevel = getpid();
|
||||
len = sizeof(rq);
|
||||
if (write(sd, &rq, len) != len)
|
||||
goto exit;
|
||||
|
||||
if (read(sd, &rq, len) != len)
|
||||
goto exit;
|
||||
|
||||
result = 0;
|
||||
exit:
|
||||
close(sd);
|
||||
return result;
|
||||
}
|
||||
|
||||
static void sighandler(int signo)
|
||||
{
|
||||
if (signo == SIGTERM)
|
||||
handover = 1;
|
||||
running = 0;
|
||||
}
|
||||
|
||||
static int init(char *progname, char *devnode, int timeout)
|
||||
{
|
||||
int fd;
|
||||
|
||||
sprintf(progname, "@finit-watchdog");
|
||||
signal(SIGTERM, sighandler);
|
||||
signal(SIGPWR, sighandler);
|
||||
|
||||
fd = open(devnode, O_WRONLY);
|
||||
if (fd == -1)
|
||||
return -1;
|
||||
|
||||
ioctl(fd, WDIOC_SETTIMEOUT, &timeout);
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
static int loop(int fd)
|
||||
{
|
||||
int done = 0;
|
||||
|
||||
while (running) {
|
||||
do_sleep(1);
|
||||
ioctl(fd, WDIOC_KEEPALIVE, &done);
|
||||
|
||||
if (!done && !notify())
|
||||
done = 1;
|
||||
}
|
||||
|
||||
if (handover)
|
||||
return !write(fd, "V", 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void watchdog(char *progname)
|
||||
{
|
||||
if (fork() == 0) {
|
||||
int fd, ret;
|
||||
|
||||
fd = init(progname, WDT_DEVNODE, WDT_TIMEOUT);
|
||||
if (fd == -1) {
|
||||
_pe("Failed connecting to watchdog %s", WDT_DEVNODE);
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
ret = loop(fd);
|
||||
close(fd);
|
||||
|
||||
_exit(ret);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
/* Built-in watchdog daemon
|
||||
*
|
||||
* Copyright (c) 2016 Joachim Nilsson <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config.h" /* Generated by configure script */
|
||||
|
||||
#define WDT_DEVNODE "/dev/watchdog"
|
||||
#define WDT_TIMEOUT 3
|
||||
|
||||
#ifdef BUILTIN_WATCHDOG
|
||||
void watchdog(char *progname);
|
||||
#else
|
||||
#define watchdog(progname)
|
||||
#endif /* BUILTIN_WATCHDOG */
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
Reference in New Issue
Block a user