mirror of
https://github.com/troglobit/finit.git
synced 2026-10-16 10:39:35 +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 |
No files matched your search
+3
-3
@@ -33,11 +33,11 @@ addons:
|
|||||||
branch_pattern: dev
|
branch_pattern: dev
|
||||||
|
|
||||||
install:
|
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
|
- 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
|
- 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)
|
- (cd libite-1.8.2 && ./configure --prefix=/tmp && make && make install-strip)
|
||||||
|
|
||||||
# Custom build script for the time being, no "make test" yet
|
# 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 \
|
sm.c sm.h \
|
||||||
svc.c svc.h \
|
svc.c svc.h \
|
||||||
tty.c tty.h \
|
tty.c tty.h \
|
||||||
|
util.c util.h \
|
||||||
utmp-api.c utmp-api.h
|
utmp-api.c utmp-api.h
|
||||||
pkginclude_HEADERS = cond.h finit.h helpers.h inetd.h plugin.h svc.h
|
pkginclude_HEADERS = cond.h finit.h helpers.h inetd.h plugin.h svc.h
|
||||||
if INETD
|
if INETD
|
||||||
finit_SOURCES += inetd.c inetd.h
|
finit_SOURCES += inetd.c inetd.h
|
||||||
endif
|
endif
|
||||||
|
if WATCHDOGD
|
||||||
|
finit_SOURCES += watchdog.c watchdog.h
|
||||||
|
endif
|
||||||
|
|
||||||
finit_CFLAGS = -W -Wall -Wextra -std=gnu99 $(lite_CFLAGS) $(uev_CFLAGS)
|
finit_CFLAGS = -W -Wall -Wextra -std=gnu99 $(lite_CFLAGS) $(uev_CFLAGS)
|
||||||
finit_LDADD = $(lite_LIBS) $(uev_LIBS)
|
finit_LDADD = $(lite_LIBS) $(uev_LIBS)
|
||||||
@@ -29,14 +33,14 @@ finit_LDADD += -ldl
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
initctl_SOURCES = initctl.c svc.c svc.h helpers.c helpers.h cond.c cond.h \
|
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_CFLAGS = $(lite_CFLAGS)
|
||||||
initctl_LDADD = $(lite_LIBS)
|
initctl_LDADD = $(lite_LIBS)
|
||||||
|
|
||||||
reboot_SOURCES = reboot.c
|
reboot_SOURCES = reboot.c util.c util.h
|
||||||
|
|
||||||
INIT_LNKS = telinit init
|
INIT_LNKS = telinit init
|
||||||
REBOOT_LNKS = shutdown halt suspend
|
REBOOT_LNKS = shutdown halt poweroff suspend
|
||||||
SUBDIRS = plugins
|
SUBDIRS = plugins
|
||||||
doc_DATA = README.md LICENSE finit.conf
|
doc_DATA = README.md LICENSE finit.conf
|
||||||
EXTRA_DIST = README.md LICENSE ChangeLog.md finit.conf
|
EXTRA_DIST = README.md LICENSE ChangeLog.md finit.conf
|
||||||
@@ -65,7 +69,7 @@ install-exec-hook:
|
|||||||
fi; \
|
fi; \
|
||||||
done
|
done
|
||||||
@if [ -L $(DESTDIR)$(sbindir)/reboot ]; then \
|
@if [ -L $(DESTDIR)$(sbindir)/reboot ]; then \
|
||||||
echo "Non-finit reboot, skipping."; \
|
echo "Non-finit reboot, skipping install."; \
|
||||||
else \
|
else \
|
||||||
for file in $(REBOOT_LNKS); do \
|
for file in $(REBOOT_LNKS); do \
|
||||||
link=$(DESTDIR)$(sbindir)/$$file; \
|
link=$(DESTDIR)$(sbindir)/$$file; \
|
||||||
|
|||||||
@@ -1,19 +1,8 @@
|
|||||||
```
|
<p align="center"><img src="images/finit3.png" alt="Finit: Fast Init" /></p>
|
||||||
_______ __ _____ ___ __ ___________ _______
|
|
||||||
/" "||" \ (\" \|" \ |" \(" _ ")/" __ )
|
|
||||||
(: ______)|| | |.\\ \ | || |)__/ \\__/(__/ _) ./
|
|
||||||
\/ | |: | |: \. \\ | |: | \\_ / / //
|
|
||||||
// ___) |. | |. \ \. | |. | |. | __ \_ \\
|
|
||||||
(: ( /\ |\| \ \ | /\ |\ \: | (: \__) :\
|
|
||||||
\__/ (__\_|_)\___|\____\)(__\_|_) \__| \_______) ... Yes, we need a new logo!
|
|
||||||
```
|
|
||||||
|
|
||||||
Fast init for Linux
|
|
||||||
===================
|
|
||||||
[![Travis Status]][Travis] [![Coverity Status]][Coverity Scan]
|
|
||||||
|
|
||||||
Table of Contents
|
Table of Contents
|
||||||
-----------------
|
-----------------
|
||||||
|
[![Travis Status]][Travis] [![Coverity Status]][Coverity Scan]
|
||||||
|
|
||||||
* [Introduction](#introduction)
|
* [Introduction](#introduction)
|
||||||
* [Features](#features)
|
* [Features](#features)
|
||||||
@@ -27,6 +16,7 @@ Table of Contents
|
|||||||
* [Rebooting & Halting](#rebooting--halting)
|
* [Rebooting & Halting](#rebooting--halting)
|
||||||
* [Commands & Status](#commands--status)
|
* [Commands & Status](#commands--status)
|
||||||
* [Building](doc/build.md#building)
|
* [Building](doc/build.md#building)
|
||||||
|
* [Requirements](#requirements)
|
||||||
* [Running](#running)
|
* [Running](#running)
|
||||||
* [Debugging](#debugging)
|
* [Debugging](#debugging)
|
||||||
* [Origin & References](#origin--references)
|
* [Origin & References](#origin--references)
|
||||||
@@ -35,11 +25,15 @@ Table of Contents
|
|||||||
Introduction
|
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
|
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,
|
[runit][3]. It also supports free-form conditions based on events, e.g.
|
||||||
although it is fully usable on server and desktop installations as well.
|
triggering on PID file creation, Netlink events like a default route or
|
||||||
See the [contrib section](contrib/) for Debian and Alpine examples.
|
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
|
Traditional [SysV init][4] style systems are scripted. For low-resource
|
||||||
embedded systems this is quite resource intensive and often leads to
|
embedded systems this is quite resource intensive and often leads to
|
||||||
@@ -140,26 +134,26 @@ nasty bits with PAM etc.
|
|||||||
|
|
||||||
**Runlevels**
|
**Runlevels**
|
||||||
|
|
||||||
Runlevels are optional in Finit, but support for [SysV runlevels][5] is
|
Support for SysV init-style [runlevels][5] is available, in the same
|
||||||
available if needed. All services in runlevel S(1) are started first,
|
minimal style as everything else in Finit. The `[2345]` syntax can be
|
||||||
followed by the desired run-time runlevel. Runlevel S can be started in
|
applied to service, task, run, inetd, and TTY stanzas.
|
||||||
sequence by using `run [S] cmd`. Changing runlevels at runtime is done
|
|
||||||
like any other init, e.g. <kbd>init 4</kbd>
|
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**
|
**Plugins**
|
||||||
|
|
||||||
Finit plugins can be *callbacks*, *boot hooks* into different stages of
|
Plugins can *extend* the functionality of Finit and *hook into* the
|
||||||
the boot process, or *pure extensions*. Plugins are written in C and
|
different stages of the boot process and at runtime. Plugins are
|
||||||
compiled into a dynamic library that is loaded automatically by finit at
|
written in C and compiled into a dynamic library loaded automatically by
|
||||||
boot. A basic set of plugins that extend and modify the basic behavior
|
finit at boot. A basic set of plugins are bundled in the `plugins/`
|
||||||
are bundled in the `plugins/` directory.
|
directory.
|
||||||
|
|
||||||
Capabilities:
|
Capabilities:
|
||||||
|
|
||||||
- **Task/Run/Service callbacks**
|
|
||||||
Modify service arguments, override service monitor's decisions to
|
|
||||||
start/stop/reload a service.
|
|
||||||
- **Hooks**
|
- **Hooks**
|
||||||
Hook into the boot at predefined points to extend Finit
|
Hook into the boot at predefined points to extend Finit
|
||||||
- **I/O**
|
- **I/O**
|
||||||
@@ -178,7 +172,7 @@ For more information, see [doc/plugins.md](doc/plugins.md).
|
|||||||
Runparts & /etc/rc.local
|
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,
|
calls its built-in [run-parts(8)][] on the `runparts <DIR>` directory,
|
||||||
and `/etc/rc.local`, in that order if they exist.
|
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,
|
To specify an allowed set of runlevels for a `service`, `run` command,
|
||||||
`task`, or `tty`, add `[NNN]` to your `/etc/finit.conf`, like this:
|
`task`, or `tty`, add `[NNN]` to your `/etc/finit.conf`, like this:
|
||||||
|
|
||||||
```shell
|
```
|
||||||
service [S12345] /sbin/syslogd -n -x -- System log daemon
|
service [S12345] /sbin/syslogd -n -x -- System log daemon
|
||||||
run [S] /etc/init.d/acpid start -- Starting ACPI Daemon
|
run [S] /etc/init.d/acpid start -- Starting ACPI Daemon
|
||||||
task [S] /etc/init.d/kbd start -- Preparing console
|
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
|
Rebooting & Halting
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
Finit is often used on embedded and small Linux systems with BusyBox.
|
Traditionally, rebooting and halting a UNIX system is done by changing
|
||||||
For compatibility with its existing toolset (halt, poweroff, reboot),
|
its runlevel. Finit comes with its own tooling providing: `shutdown`,
|
||||||
the following signals have been adopted:
|
`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`
|
For compatibility reasons Finit listens to the same set of signals as
|
||||||
Same effect as `finit q`, reloads all *.conf files in `/etc/finit.d/`
|
BusyBox init. This is not 100% compatible with SysV init, but clearly
|
||||||
* `SIGUSR1`
|
the more common combination for Finit. For more details, see
|
||||||
Calls shutdown hooks, including HOOK_SHUTDOWN, stops all running
|
[doc/signals.md](doc/signals.md).
|
||||||
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.
|
Finit also listens to the classic SysV init FIFO, used by `telinit`.
|
||||||
* `SIGUSR2`
|
Support for this is implemented by the `initctl.so` plugin. Hence,
|
||||||
Like SIGUSR1, but tell kernel to power-off the system, if ACPI
|
`telinit q` will work as the UNIX beards intended.
|
||||||
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.
|
~ # telinit -h
|
||||||
* `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, 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
|
|
||||||
Usage: telinit [OPTIONS] [q | Q | 0-9]
|
Usage: telinit [OPTIONS] [q | Q | 0-9]
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
-h, --help This help text
|
-h, --help This help text
|
||||||
-v, --version Show Finit version
|
-V, --version Show Finit version
|
||||||
|
|
||||||
Commands:
|
Commands:
|
||||||
q | Q Reload *.conf in /etc/finit.d/, like SIGHUP
|
0 Power-off the system, same as initctl poweroff
|
||||||
0 - 9 Change runlevel: 0 halt, 6 reboot
|
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
|
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
|
services, called `initctl`. Unlike `telinit` the `initctl` tool does
|
||||||
not return until the given command has fully completed.
|
not return until the given command has fully completed.
|
||||||
|
|
||||||
```shell
|
|
||||||
~ $ initctl -h
|
~ $ initctl -h
|
||||||
Usage: initctl [OPTIONS] <COMMAND>
|
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
|
restart <JOB|NAME>[:ID] Restart (stop/start) service by job# or name
|
||||||
reload <JOB|NAME>[:ID] Reload (SIGHUP) service by job# or name
|
reload <JOB|NAME>[:ID] Reload (SIGHUP) service by job# or name
|
||||||
version Show Finit version
|
version Show Finit version
|
||||||
```
|
|
||||||
|
|
||||||
The `<!>` notation to a service stanza can be used empty, then it will
|
For services *not* supporting `SIGHUP` the `<!>` notation in the .conf
|
||||||
apply to `reload` and `runlevel` commands. I.e., when a service's
|
file must be used to tell Finit to stop and start it on `reload` and
|
||||||
`.conf` file has been changed Finit will stop and start it instead. If
|
`runlevel` changes. If `<>` holds more [conditions](doc/conditions.md),
|
||||||
a service does *not* have `<!>` declared, the service will be reloaded
|
these will also affect how a service is maintained.
|
||||||
(`SIGHUP`:ed) in the `START` phase instead. The latter is the preferred
|
|
||||||
behaviour, but not all daemons support this, unfortunately.
|
|
||||||
|
|
||||||
**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
|
the current runlevel these services will not be respawned automatically
|
||||||
by Finit if they exit (crash). Hence, if the runlevel is 2, the below
|
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.
|
Dropbear SSH service will not be restarted if it is killed or exits.
|
||||||
|
|
||||||
```shell
|
|
||||||
~ $ initctl status -v
|
~ $ initctl status -v
|
||||||
1 running 476 [S12345] /sbin/watchdog -T 16 -t 2 -F /dev/watchdog
|
1 running 476 [S12345] /sbin/watchdog -T 16 -t 2 -F /dev/watchdog
|
||||||
2 running 477 [S12345] /sbin/syslogd -n -b 3 -D
|
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
|
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:1 inetd 0 [345] /sbin/dropbear allow eth0:222
|
||||||
6:2 inetd 0 [345] /sbin/dropbear allow *:22 deny eth0
|
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
|
Running
|
||||||
-------
|
-------
|
||||||
@@ -373,25 +366,29 @@ LILO, U-Boot/Barebox or RedBoot) configuration to append the following
|
|||||||
to the kernel command line:
|
to the kernel command line:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
init=/sbin/finit
|
append="init=/sbin/finit"
|
||||||
```
|
```
|
||||||
|
|
||||||
Remember to also set up an initial `/etc/finit.conf` before rebooting!
|
Remember to also set up an initial `/etc/finit.conf` before rebooting!
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
|
||||||
Debugging
|
Debugging
|
||||||
---------
|
---------
|
||||||
|
|
||||||
Add `finit_debug`, or `--debug`, to the kernel command line to enable
|
Add `finit_debug`, or `--debug`, to the kernel command line to enable
|
||||||
debug messages. See the output from `configure --help` for more on
|
debug messages.
|
||||||
how to assist debugging.
|
|
||||||
|
|
||||||
```shell
|
```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
|
Origin & References
|
||||||
-------------------
|
-------------------
|
||||||
@@ -410,6 +407,7 @@ and proposed extensions.
|
|||||||
[3]: http://smarden.org/runit/
|
[3]: http://smarden.org/runit/
|
||||||
[4]: http://en.wikipedia.org/wiki/Init
|
[4]: http://en.wikipedia.org/wiki/Init
|
||||||
[5]: http://en.wikipedia.org/wiki/Runlevel
|
[5]: http://en.wikipedia.org/wiki/Runlevel
|
||||||
|
[6]: https://www.freedesktop.org/wiki/Software/systemd/
|
||||||
[9]: https://github.com/troglobit/troglos
|
[9]: https://github.com/troglobit/troglos
|
||||||
[run-parts(8)]: http://manpages.debian.org/cgi-bin/man.cgi?query=run-parts
|
[run-parts(8)]: http://manpages.debian.org/cgi-bin/man.cgi?query=run-parts
|
||||||
[original finit]: http://helllabs.org/finit/
|
[original finit]: http://helllabs.org/finit/
|
||||||
|
|||||||
@@ -20,8 +20,6 @@ General
|
|||||||
|
|
||||||
* Add halt/poweroff/shutdown symlinks to finit and convert reboot, but
|
* Add halt/poweroff/shutdown symlinks to finit and convert reboot, but
|
||||||
only install symlinks if these tools don't already exist.
|
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.
|
* Add support for timed shutdown in Finit, including cancelled shutdown.
|
||||||
* SysV init and systemd use SIGUSR1 to restart their FIFO/D-Bus. Add
|
* SysV init and systemd use SIGUSR1 to restart their FIFO/D-Bus. Add
|
||||||
API restart to SIGHUP callback for the same functionality in Finit.
|
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
|
`service <SVC> stop|start|restart|reload|status` on top
|
||||||
* Add support for JSON output, or similar, from `initctl show`, e.g.
|
* Add support for JSON output, or similar, from `initctl show`, e.g.
|
||||||
`initctl show --json`
|
`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
|
* 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
|
Inetd
|
||||||
-----
|
-----
|
||||||
|
|
||||||
Add support for throttling connections.
|
* Add support for throttling connections.
|
||||||
|
* Optimize interface filtering by using socket filter. The functions
|
||||||
Optimize interface filtering by using socket filter. The functions
|
`inet_*_peek()` and `inetd_is_allowed()` used for interace filtering
|
||||||
`inet_*_peek()` and `inetd_is_allowed()` used for interace filtering
|
should be possible to rewrite as socket filters.
|
||||||
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
|
Crond
|
||||||
@@ -93,44 +96,6 @@ the shell -- that way setting up one-time jobs would not entail
|
|||||||
re-reading `/etc/finit.conf`
|
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
|
Documentation
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
|
|||||||
@@ -217,9 +217,14 @@ static int do_handle_emit(char *buf, size_t len)
|
|||||||
return result;
|
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))
|
static void cb(uev_t *w, void *UNUSED(arg), int UNUSED(events))
|
||||||
{
|
{
|
||||||
int sd;
|
int sd, lvl;
|
||||||
struct init_request rq;
|
struct init_request rq;
|
||||||
|
|
||||||
sd = accept(w->fd, NULL, NULL);
|
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) {
|
switch (rq.cmd) {
|
||||||
case INIT_CMD_RUNLVL:
|
case INIT_CMD_RUNLVL:
|
||||||
switch (rq.runlevel) {
|
switch (rq.runlevel) {
|
||||||
case '0':
|
|
||||||
_d("Halting system (SIGUSR2)");
|
|
||||||
do_shutdown(SHUT_OFF);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 's':
|
case 's':
|
||||||
case 'S':
|
case 'S':
|
||||||
_d("Cannot enter bootstrap after boot ...");
|
rq.runlevel = '1'; /* Single user mode */
|
||||||
rq.runlevel = '1';
|
|
||||||
/* Fall through to regular processing */
|
/* Fall through to regular processing */
|
||||||
|
|
||||||
case '1'...'5':
|
case '0'...'9':
|
||||||
case '7'...'9':
|
|
||||||
_d("Setting new runlevel %c", rq.runlevel);
|
_d("Setting new runlevel %c", rq.runlevel);
|
||||||
service_runlevel(rq.runlevel - '0');
|
lvl = rq.runlevel - '0';
|
||||||
break;
|
if (lvl == 0)
|
||||||
|
halt = SHUT_OFF;
|
||||||
case '6':
|
if (lvl == 6)
|
||||||
_d("Rebooting system (SIGUSR1)");
|
halt = SHUT_REBOOT;
|
||||||
do_shutdown(SHUT_REBOOT);
|
service_runlevel(lvl);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -319,13 +317,25 @@ static void cb(uev_t *w, void *UNUSED(arg), int UNUSED(events))
|
|||||||
|
|
||||||
case INIT_CMD_GET_RUNLEVEL:
|
case INIT_CMD_GET_RUNLEVEL:
|
||||||
rq.runlevel = runlevel;
|
rq.runlevel = runlevel;
|
||||||
result = 0;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case INIT_CMD_ACK:
|
case INIT_CMD_ACK:
|
||||||
_d("Client failed reading ACK");
|
_d("Client failed reading ACK");
|
||||||
goto leave;
|
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:
|
default:
|
||||||
_d("Unsupported cmd: %d", rq.cmd);
|
_d("Unsupported cmd: %d", rq.cmd);
|
||||||
break;
|
break;
|
||||||
@@ -347,6 +357,7 @@ leave:
|
|||||||
int api_init(uev_ctx_t *ctx)
|
int api_init(uev_ctx_t *ctx)
|
||||||
{
|
{
|
||||||
int sd;
|
int sd;
|
||||||
|
mode_t oldmask;
|
||||||
struct sockaddr_un sun = {
|
struct sockaddr_un sun = {
|
||||||
.sun_family = AF_UNIX,
|
.sun_family = AF_UNIX,
|
||||||
.sun_path = INIT_SOCKET,
|
.sun_path = INIT_SOCKET,
|
||||||
@@ -359,17 +370,20 @@ int api_init(uev_ctx_t *ctx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
erase(INIT_SOCKET);
|
erase(INIT_SOCKET);
|
||||||
|
oldmask = umask(0077);
|
||||||
if (-1 == bind(sd, (struct sockaddr*)&sun, sizeof(sun)))
|
if (-1 == bind(sd, (struct sockaddr*)&sun, sizeof(sun)))
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
if (-1 == listen(sd, 10))
|
if (-1 == listen(sd, 10))
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
|
umask(oldmask);
|
||||||
if (!uev_io_init(ctx, &api_watcher, cb, NULL, sd, UEV_READ))
|
if (!uev_io_init(ctx, &api_watcher, cb, NULL, sd, UEV_READ))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
_pe("Failed intializing API socket");
|
_pe("Failed intializing API socket");
|
||||||
|
umask(oldmask);
|
||||||
close(sd);
|
close(sd);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,7 @@
|
|||||||
#include <lite/lite.h>
|
#include <lite/lite.h>
|
||||||
|
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
static int do_send(struct init_request *rq)
|
static int do_send(struct init_request *rq)
|
||||||
{
|
{
|
||||||
@@ -39,7 +40,7 @@ static int do_send(struct init_request *rq)
|
|||||||
|
|
||||||
if (fd == -1) {
|
if (fd == -1) {
|
||||||
if (!fexist(FINIT_FIFO)) {
|
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;
|
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"
|
" q, Q Reload *.conf in /etc/finit.d/, same as initctl reload or\n"
|
||||||
" sending SIGHUP to PID 1\n"
|
" sending SIGHUP to PID 1\n"
|
||||||
" 1, s, S Enter system rescue mode, runlevel 1\n"
|
" 1, s, S Enter system rescue mode, runlevel 1\n"
|
||||||
"\n", __progname);
|
"\n", prognm);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@@ -123,6 +124,7 @@ int client(int argc, char *argv[])
|
|||||||
};
|
};
|
||||||
|
|
||||||
silent = 1;
|
silent = 1;
|
||||||
|
progname(argv[0]);
|
||||||
while ((c = getopt_long(argc, argv, "h?v", long_options, NULL)) != EOF) {
|
while ((c = getopt_long(argc, argv, "h?v", long_options, NULL)) != EOF) {
|
||||||
switch(c) {
|
switch(c) {
|
||||||
case 'v':
|
case 'v':
|
||||||
|
|||||||
@@ -89,14 +89,11 @@ static void cond_update(const char *name)
|
|||||||
svc_t *svc;
|
svc_t *svc;
|
||||||
|
|
||||||
_d("%s", name);
|
_d("%s", name);
|
||||||
if (!name)
|
|
||||||
return;
|
|
||||||
|
|
||||||
for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) {
|
for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) {
|
||||||
if (!svc_has_cond(svc) || !cond_affects(name, svc->cond))
|
if (!svc_has_cond(svc) || !cond_affects(name, svc->cond))
|
||||||
continue;
|
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);
|
service_step(svc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -197,7 +197,7 @@ void conf_parse_rlimit(char *line)
|
|||||||
} else {
|
} else {
|
||||||
const char *err = NULL;
|
const char *err = NULL;
|
||||||
|
|
||||||
new = strtonum(tok, 0, 2 << 31, &err);
|
new = strtonum(tok, 0, (long long)2 << 31, &err);
|
||||||
if (err)
|
if (err)
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
@@ -340,16 +340,13 @@ static void parse_dynamic(char *line, time_t mtime)
|
|||||||
if (MATCH_CMD(line, "#", x))
|
if (MATCH_CMD(line, "#", x))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Monitored daemon, will be respawned on exit, as
|
/* Monitored daemon, will be respawned on exit */
|
||||||
* long as the (optional) service callback returns
|
|
||||||
* non-zero */
|
|
||||||
if (MATCH_CMD(line, "service ", x)) {
|
if (MATCH_CMD(line, "service ", x)) {
|
||||||
service_register(SVC_TYPE_SERVICE, x, mtime, NULL);
|
service_register(SVC_TYPE_SERVICE, x, mtime, NULL);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* One-shot task, will not be respawned. Only runs if
|
/* One-shot task, will not be respawned */
|
||||||
* the (optional) service callback returns true */
|
|
||||||
if (MATCH_CMD(line, "task ", x)) {
|
if (MATCH_CMD(line, "task ", x)) {
|
||||||
service_register(SVC_TYPE_TASK, x, mtime, NULL);
|
service_register(SVC_TYPE_TASK, x, mtime, NULL);
|
||||||
return;
|
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_INIT_AUTOMAKE([1.11 foreign no-dist-gzip dist-xz subdir-objects])
|
||||||
AM_SILENT_RULES([yes])
|
AM_SILENT_RULES([yes])
|
||||||
|
|
||||||
@@ -33,7 +33,7 @@ AC_TYPE_UINT16_T
|
|||||||
AC_TYPE_UINT32_T
|
AC_TYPE_UINT32_T
|
||||||
|
|
||||||
# Check for required libraries
|
# 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])
|
PKG_CHECK_MODULES([lite], [libite >= 1.8.2])
|
||||||
|
|
||||||
# Check for configured Finit features
|
# 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.
|
AS_HELP_STRING([--enable-emergency-shell], [Experimental emergency fallback at boot.
|
||||||
Only use this for debugging very early boot problems with Finit.]))
|
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,
|
AC_ARG_ENABLE(rw-rootfs,
|
||||||
AS_HELP_STRING([--enable-rw-rootfs], [Remount / R/W at boot, usually not for embedded]))
|
AS_HELP_STRING([--enable-rw-rootfs], [Remount / R/W at boot, usually not for embedded]))
|
||||||
|
|
||||||
AC_ARG_ENABLE(silent,
|
AC_ARG_ENABLE(silent,
|
||||||
AS_HELP_STRING([--enable-silent], [Completely silent operation, not even boot messages]))
|
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,
|
AC_ARG_ENABLE(inetd,
|
||||||
AS_HELP_STRING([--disable-inetd], [Disable built-in inetd super server, default enabled]))
|
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]),
|
AS_HELP_STRING([--with-console=DEV], [Console to use, default: /dev/console]),
|
||||||
[console=$withval], [console=/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,
|
AC_ARG_WITH(username,
|
||||||
AS_HELP_STRING([--with-username=USER], [User for 'startx' .conf option, default: root]),
|
AS_HELP_STRING([--with-username=USER], [User for 'startx' .conf option, default: root]),
|
||||||
[username=$withval], [username=root])
|
[username=$withval], [username=root])
|
||||||
@@ -124,6 +126,9 @@ AC_ARG_WITH(random-seed,
|
|||||||
AS_IF([test "x$enable_emergency_shell" = "xyes"], [
|
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.])])
|
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"], [
|
AS_IF([test "x$enable_rw_rootfs" = "xyes"], [
|
||||||
AC_DEFINE(REMOUNT_ROOTFS, 1, [Remount / as rw at boot])])
|
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])])
|
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 ###########################################################################
|
### 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])])
|
AC_DEFINE(INETD_DISABLED, 1, [Disable built-in inetd])])
|
||||||
|
|
||||||
AS_IF([test "x$enable_quiet" != "xno"], [
|
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 ##############################################################################
|
### With features ##############################################################################
|
||||||
AS_IF([test "x$with_fifo" != "xno"], [
|
AS_IF([test "x$with_fifo" != "xno"], [
|
||||||
@@ -176,11 +185,6 @@ AS_IF([test "x$with_console" != "xno"], [
|
|||||||
console=/dev/console])])
|
console=/dev/console])])
|
||||||
AC_DEFINE_UNQUOTED(CONSOLE, "$console", [Default console to use])
|
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$with_username" != "xno"], [
|
||||||
AS_IF([test "x$username" = "xyes"], [
|
AS_IF([test "x$username" = "xyes"], [
|
||||||
username=root])])
|
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.])])
|
AC_DEFINE_UNQUOTED(RANDOMSEED, "$lurvig", [Improve random at boot by seeding it with sth from before.])])
|
||||||
|
|
||||||
# Control build with automake flags
|
# Control build with automake flags
|
||||||
AM_CONDITIONAL(STATIC, [test "x$enable_static" = "xyes"])
|
AM_CONDITIONAL(STATIC, [test "x$enable_static" = "xyes"])
|
||||||
AM_CONDITIONAL(INETD, [test "x$enable_inetd" = "xyes"])
|
AM_CONDITIONAL(INETD, [test "x$enable_inetd" = "xyes"])
|
||||||
|
AM_CONDITIONAL(WATCHDOGD, [test "x$enable_watchdog" = "xyes"])
|
||||||
|
|
||||||
# Generate all files
|
# Generate all files
|
||||||
AC_OUTPUT
|
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,
|
`log` to redirect `stderr` and `stdout` of the application to syslog,
|
||||||
using `logger`.
|
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
|
/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();
|
pid = fork();
|
||||||
if (0 == pid) {
|
if (0 == pid) {
|
||||||
int i;
|
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
struct sigaction sa;
|
|
||||||
|
|
||||||
/* Reset signal handlers that were set by the parent process */
|
/* Reset signal handlers that were set by the parent process */
|
||||||
for (i = 1; i < NSIG; i++)
|
sig_unblock();
|
||||||
DFLSIG(sa, i, 0);
|
setsid();
|
||||||
|
|
||||||
/* Always redirect stdio for run() */
|
/* Always redirect stdio for run() */
|
||||||
fp = fopen("/dev/null", "w");
|
fp = fopen("/dev/null", "w");
|
||||||
|
|||||||
@@ -25,7 +25,6 @@
|
|||||||
#include "config.h" /* Generated by configure script */
|
#include "config.h" /* Generated by configure script */
|
||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <glob.h>
|
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#ifdef HAVE_FSTAB_H
|
#ifdef HAVE_FSTAB_H
|
||||||
#include <fstab.h>
|
#include <fstab.h>
|
||||||
@@ -46,10 +45,12 @@
|
|||||||
#include "sm.h"
|
#include "sm.h"
|
||||||
#include "tty.h"
|
#include "tty.h"
|
||||||
#include "utmp-api.h"
|
#include "utmp-api.h"
|
||||||
|
#include "watchdog.h"
|
||||||
|
|
||||||
int debug = 0;
|
int debug = 0;
|
||||||
int quiet = QUIET_MODE; /* Delayed disable of silent mode. */
|
int quiet = QUIET_MODE; /* Delayed disable of silent mode. */
|
||||||
int silent = SILENT_MODE; /* Completely silent, including boot */
|
int silent = SILENT_MODE; /* Completely silent, including boot */
|
||||||
|
int wdogpid = 0; /* No watchdog by default */
|
||||||
int runlevel = 0; /* Bootstrap 'S' */
|
int runlevel = 0; /* Bootstrap 'S' */
|
||||||
int cfglevel = RUNLEVEL; /* Fallback if no configured runlevel */
|
int cfglevel = RUNLEVEL; /* Fallback if no configured runlevel */
|
||||||
int prevlevel = -1;
|
int prevlevel = -1;
|
||||||
@@ -119,26 +120,7 @@ static int fsck(int pass)
|
|||||||
|
|
||||||
static void networking(void)
|
static void networking(void)
|
||||||
{
|
{
|
||||||
size_t i;
|
|
||||||
glob_t gl;
|
|
||||||
FILE *fp;
|
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 */
|
/* Run user network start script if enabled */
|
||||||
if (network) {
|
if (network) {
|
||||||
@@ -149,7 +131,8 @@ static void networking(void)
|
|||||||
/* Debian/Ubuntu/Busybox interfaces file */
|
/* Debian/Ubuntu/Busybox interfaces file */
|
||||||
fp = fopen("/etc/network/interfaces", "r");
|
fp = fopen("/etc/network/interfaces", "r");
|
||||||
if (fp) {
|
if (fp) {
|
||||||
i = 0;
|
int i = 0;
|
||||||
|
char buf[160];
|
||||||
|
|
||||||
/* Bring up all 'auto' interfaces */
|
/* Bring up all 'auto' interfaces */
|
||||||
while (fgets(buf, sizeof(buf), fp)) {
|
while (fgets(buf, sizeof(buf), fp)) {
|
||||||
@@ -232,7 +215,6 @@ static void emergency_shell(void)
|
|||||||
|
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
int err;
|
|
||||||
char *devfsd;
|
char *devfsd;
|
||||||
uev_ctx_t loop;
|
uev_ctx_t loop;
|
||||||
|
|
||||||
@@ -325,7 +307,13 @@ int main(int argc, char* argv[])
|
|||||||
else
|
else
|
||||||
devfsd = "/lib/systemd/systemd-udevd --daemon";
|
devfsd = "/lib/systemd/systemd-udevd --daemon";
|
||||||
}
|
}
|
||||||
|
|
||||||
run_interactive(devfsd, "Populating device tree");
|
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
|
* Load plugins first, finit.conf may contain references to
|
||||||
@@ -338,6 +326,11 @@ int main(int argc, char* argv[])
|
|||||||
*/
|
*/
|
||||||
conf_parse_config();
|
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 as soon as possible, for syslog et al. */
|
||||||
set_hostname(&hostname);
|
set_hostname(&hostname);
|
||||||
|
|
||||||
@@ -362,19 +355,12 @@ int main(int argc, char* argv[])
|
|||||||
plugin_run_hooks(HOOK_ROOTFS_UP);
|
plugin_run_hooks(HOOK_ROOTFS_UP);
|
||||||
|
|
||||||
umask(0);
|
umask(0);
|
||||||
print_desc("Mounting filesystems", NULL);
|
if (run_interactive("/bin/mount -na", "Mounting filesystems"))
|
||||||
|
|
||||||
err = run("/bin/mount -na");
|
|
||||||
print_result(err);
|
|
||||||
if (err)
|
|
||||||
plugin_run_hooks(HOOK_MOUNT_ERROR);
|
plugin_run_hooks(HOOK_MOUNT_ERROR);
|
||||||
|
|
||||||
run("/sbin/swapon -ea");
|
run("/sbin/swapon -ea");
|
||||||
umask(0022);
|
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 */
|
/* Base FS up, enable standard SysV init signals */
|
||||||
sig_setup(&loop);
|
sig_setup(&loop);
|
||||||
|
|
||||||
@@ -410,11 +396,14 @@ int main(int argc, char* argv[])
|
|||||||
if (runparts && fisdir(runparts)) {
|
if (runparts && fisdir(runparts)) {
|
||||||
_d("Running startup scripts in %s ...", runparts);
|
_d("Running startup scripts in %s ...", runparts);
|
||||||
run_parts(runparts, NULL);
|
run_parts(runparts, NULL);
|
||||||
|
service_reload_dynamic();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Convenient SysV compat for when you just don't care ... */
|
/* 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);
|
run_interactive(FINIT_RC_LOCAL, "Calling %s", FINIT_RC_LOCAL);
|
||||||
|
service_reload_dynamic();
|
||||||
|
}
|
||||||
|
|
||||||
/* Hooks that should run at the very end */
|
/* Hooks that should run at the very end */
|
||||||
plugin_run_hooks(HOOK_SYSTEM_UP);
|
plugin_run_hooks(HOOK_SYSTEM_UP);
|
||||||
|
|||||||
@@ -63,10 +63,11 @@
|
|||||||
#define INIT_CMD_START_SVC 10
|
#define INIT_CMD_START_SVC 10
|
||||||
#define INIT_CMD_STOP_SVC 11
|
#define INIT_CMD_STOP_SVC 11
|
||||||
#define INIT_CMD_RELOAD_SVC 12 /* SIGHUP service */
|
#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_QUERY_INETD 14
|
||||||
#define INIT_CMD_EMIT 15
|
#define INIT_CMD_EMIT 15
|
||||||
#define INIT_CMD_GET_RUNLEVEL 16
|
#define INIT_CMD_GET_RUNLEVEL 16
|
||||||
|
#define INIT_CMD_WDOG_HELLO 128 /* Watchdog register and hello */
|
||||||
#define INIT_CMD_NACK 254
|
#define INIT_CMD_NACK 254
|
||||||
#define INIT_CMD_ACK 255
|
#define INIT_CMD_ACK 255
|
||||||
|
|
||||||
@@ -81,6 +82,7 @@ struct init_request {
|
|||||||
extern int debug;
|
extern int debug;
|
||||||
extern int quiet;
|
extern int quiet;
|
||||||
extern int silent;
|
extern int silent;
|
||||||
|
extern int wdogpid;
|
||||||
extern int runlevel;
|
extern int runlevel;
|
||||||
extern int cfglevel;
|
extern int cfglevel;
|
||||||
extern int prevlevel;
|
extern int prevlevel;
|
||||||
@@ -93,8 +95,6 @@ extern char *runparts;
|
|||||||
extern char *console;
|
extern char *console;
|
||||||
extern uev_ctx_t *ctx;
|
extern uev_ctx_t *ctx;
|
||||||
|
|
||||||
extern char *__progname;
|
|
||||||
|
|
||||||
#endif /* FINIT_H_ */
|
#endif /* FINIT_H_ */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -28,6 +28,7 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include <sys/utsname.h>
|
#include <sys/utsname.h>
|
||||||
|
#include <sys/ttydefaults.h> /* Not included by default in musl libc */
|
||||||
#include <termios.h>
|
#include <termios.h>
|
||||||
|
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
@@ -73,13 +74,34 @@ static void stty(int fd, speed_t speed)
|
|||||||
cfsetispeed(&term, speed);
|
cfsetispeed(&term, speed);
|
||||||
cfsetospeed(&term, speed);
|
cfsetospeed(&term, speed);
|
||||||
tcsetattr(fd, TCSAFLUSH, &term);
|
tcsetattr(fd, TCSAFLUSH, &term);
|
||||||
|
|
||||||
tcflush(fd, TCIOFLUSH);
|
tcflush(fd, TCIOFLUSH);
|
||||||
|
|
||||||
/* Clear screen -- disabled until we decide on config to disable/enable */
|
/* Disable modem specific flags */
|
||||||
//print("\033[r\033[H\033[J");
|
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
|
* 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
|
* Log to /dev/kmsg until syslogd has started, then openlog()
|
||||||
* logging as a regular daemon.
|
* 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"
|
|
||||||
*/
|
*/
|
||||||
void logit(int prio, const char *fmt, ...)
|
void logit(int prio, const char *fmt, ...)
|
||||||
{
|
{
|
||||||
@@ -197,12 +194,15 @@ void logit(int prio, const char *fmt, ...)
|
|||||||
|
|
||||||
fp = fopen("/dev/kmsg", "w");
|
fp = fopen("/dev/kmsg", "w");
|
||||||
if (fp) {
|
if (fp) {
|
||||||
|
if (debug)
|
||||||
|
prio = LOG_ERR;
|
||||||
|
|
||||||
fprintf(fp, "<%d>finit[1]:", LOG_DAEMON | prio);
|
fprintf(fp, "<%d>finit[1]:", LOG_DAEMON | prio);
|
||||||
vfprintf(fp, fmt, ap);
|
vfprintf(fp, fmt, ap);
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "Failed opening /dev/kmsg for appending ...\n");
|
fprintf(stderr, "Failed opening /dev/kmsg for appending ...\n");
|
||||||
if (prio <= LOG_ERR)
|
if (debug || prio <= LOG_ERR)
|
||||||
vfprintf(stderr, fmt, ap);
|
vfprintf(stderr, fmt, ap);
|
||||||
}
|
}
|
||||||
va_end(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;
|
int service_num;
|
||||||
static struct servent lfs;
|
static struct servent lfs;
|
||||||
|
|
||||||
@@ -339,29 +338,50 @@ static struct servent *getent_service(char *service, char *proto)
|
|||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct servent *getent_service(char *service, char *proto)
|
||||||
|
{
|
||||||
|
struct servent *ent;
|
||||||
|
|
||||||
|
#ifdef ENABLE_STATIC
|
||||||
|
ent = fallback_service(service, proto);
|
||||||
#else
|
#else
|
||||||
return getservbyname(service, proto);
|
ent = getservbyname(service, proto);
|
||||||
|
if (!ent)
|
||||||
|
ent = fallback_service(service, proto);
|
||||||
#endif
|
#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)
|
static struct protoent *getent_proto(char *proto)
|
||||||
{
|
{
|
||||||
|
struct protoent *ent;
|
||||||
|
|
||||||
#ifdef ENABLE_STATIC
|
#ifdef ENABLE_STATIC
|
||||||
int proto_num;
|
ent = fallback_proto(proto);
|
||||||
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;
|
|
||||||
#else
|
#else
|
||||||
return getprotobyname(proto);
|
ent = getprotobyname(proto);
|
||||||
|
if (!ent)
|
||||||
|
ent = fallback_proto(proto);
|
||||||
#endif
|
#endif
|
||||||
|
return ent;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int getent(char *service, char *proto, struct servent **sv, struct protoent **pv)
|
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;
|
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
|
* 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
|
* ifname is given as argument this means *only* run service on this
|
||||||
|
|||||||
@@ -54,22 +54,23 @@ typedef struct {
|
|||||||
TAILQ_HEAD(, inetd_filter) filters;
|
TAILQ_HEAD(, inetd_filter) filters;
|
||||||
} inetd_t;
|
} 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);
|
int inetd_start (inetd_t *inetd);
|
||||||
void inetd_stop (inetd_t *inetd);
|
void inetd_stop (inetd_t *inetd);
|
||||||
|
|
||||||
int inetd_new (inetd_t *inetd, char *name, char *service, char *proto,
|
int inetd_new (inetd_t *inetd, char *name, char *service, char *proto, int forking, svc_t *svc);
|
||||||
int forking, svc_t *svc);
|
int inetd_del (inetd_t *inetd);
|
||||||
int inetd_del (inetd_t *inetd);
|
|
||||||
|
|
||||||
int inetd_match (inetd_t *inetd, char *service, char *proto);
|
svc_t *inetd_find_svc (char *path, char *service, char *proto);
|
||||||
int inetd_filter_str (inetd_t *inetd, char *str, size_t len);
|
|
||||||
|
|
||||||
int inetd_flush (inetd_t *inetd);
|
int inetd_match (inetd_t *inetd, char *service, char *proto);
|
||||||
int inetd_allow (inetd_t *inetd, char *ifname);
|
int inetd_filter_str(inetd_t *inetd, char *str, size_t len);
|
||||||
int inetd_deny (inetd_t *inetd, char *ifname);
|
|
||||||
int inetd_is_allowed (inetd_t *inetd, char *ifname);
|
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_ */
|
#endif /* FINIT_INETD_H_ */
|
||||||
|
|
||||||
|
|||||||
@@ -38,6 +38,7 @@
|
|||||||
#include "cond.h"
|
#include "cond.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
#include "service.h"
|
#include "service.h"
|
||||||
|
#include "util.h"
|
||||||
#include "utmp-api.h"
|
#include "utmp-api.h"
|
||||||
|
|
||||||
#define _PATH_COND _PATH_VARRUN "finit/cond/"
|
#define _PATH_COND _PATH_VARRUN "finit/cond/"
|
||||||
@@ -439,7 +440,7 @@ static int usage(int rc)
|
|||||||
" halt Halt system\n"
|
" halt Halt system\n"
|
||||||
" poweroff Halt and power off system\n"
|
" poweroff Halt and power off system\n"
|
||||||
" utmp show Raw dump of UTMP/WTMP db\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;
|
return rc;
|
||||||
}
|
}
|
||||||
@@ -471,6 +472,7 @@ int main(int argc, char *argv[])
|
|||||||
{NULL, 0, NULL, 0}
|
{NULL, 0, NULL, 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
progname(argv[0]);
|
||||||
while ((c = getopt_long(argc, argv, "dh?v", long_options, NULL)) != EOF) {
|
while ((c = getopt_long(argc, argv, "dh?v", long_options, NULL)) != EOF) {
|
||||||
switch(c) {
|
switch(c) {
|
||||||
case 'h':
|
case 'h':
|
||||||
|
|||||||
+3
-2
@@ -1,11 +1,12 @@
|
|||||||
AM_LDFLAGS = -module -avoid-version -shared
|
AM_LDFLAGS = -module -avoid-version -shared
|
||||||
|
AM_CFLAGS = -W -Wall -Wextra -std=gnu99
|
||||||
AM_CPPFLAGS = -U_FORTIFY_SOURCE
|
AM_CPPFLAGS = -U_FORTIFY_SOURCE
|
||||||
AM_CPPFLAGS += -D_XOPEN_SOURCE=600 -D_BSD_SOURCE -D_GNU_SOURCE -D_DEFAULT_SOURCE
|
AM_CPPFLAGS += -D_XOPEN_SOURCE=600 -D_BSD_SOURCE -D_GNU_SOURCE -D_DEFAULT_SOURCE
|
||||||
AM_CPPFLAGS += $(lite_CFLAGS)
|
AM_CPPFLAGS += $(lite_CFLAGS)
|
||||||
|
|
||||||
if STATIC
|
if STATIC
|
||||||
noinst_LTLIBRARIES = libplug.la
|
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
|
if BUILD_ALSA_UTILS_PLUGIN
|
||||||
libplug_la_SOURCES += alsa-utils.c
|
libplug_la_SOURCES += alsa-utils.c
|
||||||
@@ -50,7 +51,7 @@ libplug_la_SOURCES += resolvconf.c
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
else
|
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
|
if BUILD_ALSA_UTILS_PLUGIN
|
||||||
pkglib_LTLIBRARIES += alsa-utils.la
|
pkglib_LTLIBRARIES += alsa-utils.la
|
||||||
|
|||||||
+69
-1
@@ -21,6 +21,8 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <ftw.h>
|
||||||
|
#include <mntent.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <lite/lite.h>
|
#include <lite/lite.h>
|
||||||
|
|
||||||
@@ -30,12 +32,73 @@
|
|||||||
#include "../plugin.h"
|
#include "../plugin.h"
|
||||||
#include "../utmp-api.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)
|
static void create(char *path, mode_t mode, uid_t uid, gid_t gid)
|
||||||
{
|
{
|
||||||
if (touch(path) || chmod(path, mode) || chown(path, uid, gid))
|
if (touch(path) || chmod(path, mode) || chown(path, uid, gid))
|
||||||
_w("Failed creating %s properl.", path);
|
_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
|
* 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;
|
int gid;
|
||||||
|
|
||||||
|
/* Cleanup stale files, if any still linger on. */
|
||||||
|
bootclean();
|
||||||
|
|
||||||
_d("Setting up FHS structure in /var ...");
|
_d("Setting up FHS structure in /var ...");
|
||||||
|
umask(0);
|
||||||
makedir("/var/cache", 0755);
|
makedir("/var/cache", 0755);
|
||||||
makedir("/var/games", 0755);
|
makedir("/var/games", 0755);
|
||||||
makedir("/var/lib", 0755);
|
makedir("/var/lib", 0755);
|
||||||
@@ -60,7 +127,6 @@ static void setup(void *UNUSED(arg))
|
|||||||
makedir("/var/lock", 1777);
|
makedir("/var/lock", 1777);
|
||||||
makedir("/var/run", 0755);
|
makedir("/var/run", 0755);
|
||||||
}
|
}
|
||||||
makedir("/var/lock/subsys",0755); /* Needed by D-Bus plugin */
|
|
||||||
makedir("/var/log", 0755);
|
makedir("/var/log", 0755);
|
||||||
makedir("/var/mail", 0755);
|
makedir("/var/mail", 0755);
|
||||||
makedir("/var/opt", 0755);
|
makedir("/var/opt", 0755);
|
||||||
@@ -104,6 +170,8 @@ static void setup(void *UNUSED(arg))
|
|||||||
makedir("/var/run/sshd", 01755); /* OpenSSH */
|
makedir("/var/run/sshd", 01755); /* OpenSSH */
|
||||||
makefifo("/dev/xconsole", 0640); /* sysklogd */
|
makefifo("/dev/xconsole", 0640); /* sysklogd */
|
||||||
chown("/dev/xconsole", 0, getgroup("tty"));
|
chown("/dev/xconsole", 0, getgroup("tty"));
|
||||||
|
|
||||||
|
umask(022);
|
||||||
}
|
}
|
||||||
|
|
||||||
static plugin_t plugin = {
|
static plugin_t plugin = {
|
||||||
|
|||||||
+14
-8
@@ -30,25 +30,32 @@
|
|||||||
#define NAME "chargen"
|
#define NAME "chargen"
|
||||||
#define PATTERN "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ "
|
#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;
|
static size_t pos = 0;
|
||||||
const char pattern[] = PATTERN;
|
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)) {
|
if (pos + len > sizeof(pattern)) {
|
||||||
num = sizeof(pattern) - pos;
|
num = sizeof(pattern) - pos;
|
||||||
len -= num;
|
len -= num;
|
||||||
} else {
|
} else {
|
||||||
num = 72;
|
num = width;
|
||||||
|
if (num + 3 > buflen)
|
||||||
|
num = buflen - 3;
|
||||||
len = 0;
|
len = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
strncpy(&buf[0], &pattern[pos], num--);
|
strncpy(buf, &pattern[pos], num--);
|
||||||
if (len++)
|
if (len++)
|
||||||
strncpy(&buf[num], pattern, len);
|
strncpy(&buf[num], pattern, len);
|
||||||
strcat(buf, "\r\n");
|
strlcat(buf, "\r\n", width);
|
||||||
|
|
||||||
if (++pos >= sizeof(pattern) - 1)
|
if (++pos >= sizeof(pattern) - 1)
|
||||||
pos = 0;
|
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);
|
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;
|
int sd = STDIN_FILENO;
|
||||||
ssize_t len;
|
|
||||||
char buf[BUFSIZ];
|
char buf[BUFSIZ];
|
||||||
struct sockaddr_storage sa;
|
struct sockaddr_storage sa;
|
||||||
socklen_t sa_len = sizeof(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);
|
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;
|
int sd = STDIN_FILENO;
|
||||||
char buf[BUFSIZ];
|
char buf[BUFSIZ];
|
||||||
|
|||||||
@@ -31,12 +31,17 @@
|
|||||||
|
|
||||||
static void setup(void *UNUSED(arg))
|
static void setup(void *UNUSED(arg))
|
||||||
{
|
{
|
||||||
|
umask(0);
|
||||||
|
|
||||||
_d("Starting D-Bus ...");
|
_d("Starting D-Bus ...");
|
||||||
makedir("/var/run/dbus", 0755);
|
makedir("/var/run/dbus", 0755);
|
||||||
|
makedir("/var/lock/subsys", 0755);
|
||||||
makedir("/var/lock/subsys/messagebus", 0755);
|
makedir("/var/lock/subsys/messagebus", 0755);
|
||||||
run("dbus-uuidgen --ensure");
|
run("dbus-uuidgen --ensure");
|
||||||
erase("/var/run/dbus/pid");
|
erase("/var/run/dbus/pid");
|
||||||
run_interactive("dbus-daemon --system", "Starting D-Bus");
|
run_interactive("dbus-daemon --system", "Starting D-Bus");
|
||||||
|
|
||||||
|
umask(022);
|
||||||
}
|
}
|
||||||
|
|
||||||
static plugin_t plugin = {
|
static plugin_t plugin = {
|
||||||
|
|||||||
+1
-1
@@ -27,7 +27,7 @@
|
|||||||
|
|
||||||
#include "../plugin.h"
|
#include "../plugin.h"
|
||||||
|
|
||||||
static int cb(int type)
|
static int cb(int UNUSED(type))
|
||||||
{
|
{
|
||||||
int sd = STDIN_FILENO;
|
int sd = STDIN_FILENO;
|
||||||
char buf[BUFSIZ];
|
char buf[BUFSIZ];
|
||||||
|
|||||||
+10
-21
@@ -39,13 +39,6 @@
|
|||||||
#include "../sig.h"
|
#include "../sig.h"
|
||||||
#include "../service.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 parse(void *arg, int fd, int events);
|
||||||
static void setup(void *arg);
|
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.
|
* 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))
|
static void parse(void *UNUSED(arg), int fd, int UNUSED(events))
|
||||||
{
|
{
|
||||||
|
int lvl;
|
||||||
struct init_request rq;
|
struct init_request rq;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
@@ -132,25 +129,17 @@ static void parse(void *UNUSED(arg), int fd, int UNUSED(events))
|
|||||||
switch (rq.cmd) {
|
switch (rq.cmd) {
|
||||||
case INIT_CMD_RUNLVL:
|
case INIT_CMD_RUNLVL:
|
||||||
switch (rq.runlevel) {
|
switch (rq.runlevel) {
|
||||||
case '0':
|
|
||||||
_d("Halting system (SIGUSR1 or SIGUSR2)");
|
|
||||||
do_shutdown(halt);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 's':
|
case 's':
|
||||||
case 'S':
|
case 'S':
|
||||||
rq.runlevel = '1';
|
rq.runlevel = '1';
|
||||||
/* Fall through to regular processing */
|
/* Fall through to regular processing */
|
||||||
|
|
||||||
case '1'...'5':
|
case '0'...'9':
|
||||||
case '7'...'9':
|
|
||||||
_d("Setting new runlevel %c", rq.runlevel);
|
_d("Setting new runlevel %c", rq.runlevel);
|
||||||
service_runlevel(rq.runlevel - '0');
|
lvl = rq.runlevel - '0';
|
||||||
break;
|
if (lvl == 6)
|
||||||
|
halt = SHUT_REBOOT;
|
||||||
case '6':
|
service_runlevel(lvl);
|
||||||
_d("Rebooting system (SIGTERM)");
|
|
||||||
do_shutdown(SHUT_REBOOT);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
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 "../helpers.h"
|
||||||
#include "../plugin.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))
|
static void setup(void *UNUSED(arg))
|
||||||
{
|
{
|
||||||
#ifdef USE_ETC_RESOLVCONF_RUN
|
|
||||||
DIR *dir;
|
|
||||||
struct dirent *d;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
_d("Setting up the resolver ...");
|
_d("Setting up the resolver ...");
|
||||||
#ifdef USE_ETC_RESOLVCONF_RUN
|
mkpath("/etc/resolvconf", 0755);
|
||||||
makepath("/dev/shm/network");
|
mkpath("/etc/resolvconf/run", 0755);
|
||||||
makepath("/dev/shm/resolvconf/interface");
|
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");
|
touch("/etc/resolvconf/run/enable-updates");
|
||||||
|
|
||||||
chdir("/etc/resolvconf/run/interface");
|
chdir("/etc/resolvconf/run/interface");
|
||||||
run_parts("/etc/resolvconf/update.d", "-i");
|
run_parts("/etc/resolvconf/update.d", "-i");
|
||||||
chdir("/");
|
chdir("/");
|
||||||
#endif /* USE_ETC_RESOLVCONF_RUN */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static plugin_t plugin = {
|
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;
|
char *now;
|
||||||
|
|
||||||
now = rfctime(buf, &len);
|
now = rfctime(buf, (size_t *)&len);
|
||||||
if (!now)
|
if (!now)
|
||||||
return -1; /* On error, close connection. */
|
return -1; /* On error, close connection. */
|
||||||
|
|
||||||
return sendto(sd, now, len, MSG_DONTWAIT, sa, sa_len);
|
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;
|
int sd = STDIN_FILENO;
|
||||||
char buf[BUFSIZ];
|
char buf[BUFSIZ];
|
||||||
|
|||||||
@@ -37,6 +37,8 @@ static void setup(void *UNUSED(arg))
|
|||||||
#endif
|
#endif
|
||||||
char line[LINE_SIZE];
|
char line[LINE_SIZE];
|
||||||
|
|
||||||
|
umask(0);
|
||||||
|
|
||||||
makedir("/var/run/console", 01777);
|
makedir("/var/run/console", 01777);
|
||||||
snprintf(line, sizeof(line), "/var/run/console/%s", username);
|
snprintf(line, sizeof(line), "/var/run/console/%s", username);
|
||||||
touch(line);
|
touch(line);
|
||||||
@@ -54,6 +56,8 @@ static void setup(void *UNUSED(arg))
|
|||||||
|
|
||||||
if (fexist("/sbin/restorecon"))
|
if (fexist("/sbin/restorecon"))
|
||||||
run("/sbin/restorecon /tmp/.ICE-unix /tmp/.X11-unix");
|
run("/sbin/restorecon /tmp/.ICE-unix /tmp/.X11-unix");
|
||||||
|
|
||||||
|
umask(022);
|
||||||
}
|
}
|
||||||
|
|
||||||
static plugin_t plugin = {
|
static plugin_t plugin = {
|
||||||
|
|||||||
@@ -28,6 +28,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/reboot.h>
|
#include <sys/reboot.h>
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
#ifndef RB_SW_SUSPEND /* Since Linux 2.5.18, but not in GLIBC until 2.19 */
|
#ifndef RB_SW_SUSPEND /* Since Linux 2.5.18, but not in GLIBC until 2.19 */
|
||||||
#define RB_SW_SUSPEND 0xd000fce2
|
#define RB_SW_SUSPEND 0xd000fce2
|
||||||
@@ -43,16 +44,15 @@ typedef enum {
|
|||||||
|
|
||||||
static cmd_t cmd = CMD_UNKNOWN;
|
static cmd_t cmd = CMD_UNKNOWN;
|
||||||
static char *msg = NULL;
|
static char *msg = NULL;
|
||||||
extern char *__progname;
|
|
||||||
|
|
||||||
static void translate(void)
|
static void translate(void)
|
||||||
{
|
{
|
||||||
if (cmd == CMD_UNKNOWN) {
|
if (cmd == CMD_UNKNOWN) {
|
||||||
if (!strcmp(__progname, "halt") || !strcmp(__progname, "shutdown"))
|
if (!strcmp(prognm, "halt") || !strcmp(prognm, "shutdown"))
|
||||||
cmd = CMD_HALT;
|
cmd = CMD_HALT;
|
||||||
else if (!strcmp(__progname, "poweroff"))
|
else if (!strcmp(prognm, "poweroff"))
|
||||||
cmd = CMD_POWEROFF;
|
cmd = CMD_POWEROFF;
|
||||||
else if (!strcmp(__progname, "suspend"))
|
else if (!strcmp(prognm, "suspend"))
|
||||||
cmd = CMD_SUSPEND;
|
cmd = CMD_SUSPEND;
|
||||||
else
|
else
|
||||||
cmd = CMD_REBOOT;
|
cmd = CMD_REBOOT;
|
||||||
@@ -91,7 +91,7 @@ static int usage(int rc)
|
|||||||
" --halt Halt system, regardless of how the command is called.\n"
|
" --halt Halt system, regardless of how the command is called.\n"
|
||||||
" -p, --poweroff Power-off 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"
|
" --reboot Reboot system, regardless of how the command is called.\n"
|
||||||
"\n", __progname, msg);
|
"\n", prognm, msg);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@@ -109,6 +109,7 @@ int main(int argc, char *argv[])
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* Initial command taken from program name */
|
/* Initial command taken from program name */
|
||||||
|
progname(argv[0]);
|
||||||
translate();
|
translate();
|
||||||
|
|
||||||
while ((c = getopt_long(argc, argv, "h?fHpr", long_options, NULL)) != EOF) {
|
while ((c = getopt_long(argc, argv, "h?fHpr", long_options, NULL)) != EOF) {
|
||||||
@@ -191,6 +192,8 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
if (c)
|
if (c)
|
||||||
err(1, "Failed signalling init to %s", msg);
|
err(1, "Failed signalling init to %s", msg);
|
||||||
|
else
|
||||||
|
sleep(2);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,8 @@
|
|||||||
|
|
||||||
#include "config.h" /* Generated by configure script */
|
#include "config.h" /* Generated by configure script */
|
||||||
|
|
||||||
|
#include <ctype.h> /* isblank() */
|
||||||
|
#include <sched.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <net/if.h>
|
#include <net/if.h>
|
||||||
@@ -41,11 +43,8 @@
|
|||||||
#include "tty.h"
|
#include "tty.h"
|
||||||
#include "utmp-api.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?
|
* 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
|
* 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
|
* Calls the callback registered with the call to
|
||||||
* service_timeout_after().
|
* 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);
|
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.
|
* @return 0 on success, non-zero on error.
|
||||||
*/
|
*/
|
||||||
static int service_timeout_after(svc_t *svc, int timeout,
|
static int service_timeout_after(svc_t *svc, int timeout, void (*cb)(svc_t *svc))
|
||||||
void (*cb)(svc_t *svc))
|
|
||||||
{
|
{
|
||||||
if (svc->timer_cb)
|
if (svc->timer_cb)
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
|
|
||||||
svc->timer_cb = cb;
|
svc->timer_cb = cb;
|
||||||
return uev_timer_init(ctx, &svc->timer, service_timeout_cb,
|
return uev_timer_init(ctx, &svc->timer, service_timeout_cb, svc, timeout, 0);
|
||||||
svc, timeout, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -124,26 +122,10 @@ static int service_timeout_cancel(svc_t *svc)
|
|||||||
|
|
||||||
err = uev_timer_stop(&svc->timer);
|
err = uev_timer_stop(&svc->timer);
|
||||||
svc->timer_cb = NULL;
|
svc->timer_cb = NULL;
|
||||||
|
|
||||||
return err;
|
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)
|
static int is_norespawn(void)
|
||||||
{
|
{
|
||||||
return sig_stopped() ||
|
return sig_stopped() ||
|
||||||
@@ -204,7 +186,7 @@ static int service_start(svc_t *svc)
|
|||||||
/* Declare we're waiting for svc to create its pidfile */
|
/* Declare we're waiting for svc to create its pidfile */
|
||||||
svc_starting(svc);
|
svc_starting(svc);
|
||||||
|
|
||||||
/* Block sigchild while forking. */
|
/* Block SIGCHLD while forking. */
|
||||||
sigemptyset(&nmask);
|
sigemptyset(&nmask);
|
||||||
sigaddset(&nmask, SIGCHLD);
|
sigaddset(&nmask, SIGCHLD);
|
||||||
sigprocmask(SIG_BLOCK, &nmask, &omask);
|
sigprocmask(SIG_BLOCK, &nmask, &omask);
|
||||||
@@ -486,6 +468,20 @@ void service_reload_dynamic(void)
|
|||||||
*/
|
*/
|
||||||
void service_runlevel(int newlevel)
|
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_set_runlevel(&sm, newlevel);
|
||||||
sm_step(&sm);
|
sm_step(&sm);
|
||||||
}
|
}
|
||||||
@@ -564,6 +560,9 @@ int service_register(int type, char *line, time_t mtime, char *username)
|
|||||||
if (desc) {
|
if (desc) {
|
||||||
*desc = 0;
|
*desc = 0;
|
||||||
desc += 3;
|
desc += 3;
|
||||||
|
|
||||||
|
while (*desc && isblank(*desc))
|
||||||
|
desc++;
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd = strtok(line, " ");
|
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. */
|
/* 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)
|
if (svc)
|
||||||
goto inetd_setup;
|
goto inetd_setup;
|
||||||
|
|
||||||
@@ -701,7 +700,7 @@ recreate:
|
|||||||
name = plugin->name;
|
name = plugin->name;
|
||||||
|
|
||||||
if (inetd_new(&svc->inetd, name, service, proto, forking, svc)) {
|
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);
|
return svc_del(svc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -724,6 +723,7 @@ recreate:
|
|||||||
|
|
||||||
/* New, recently modified or unchanged ... used on reload. */
|
/* New, recently modified or unchanged ... used on reload. */
|
||||||
svc_check_dirty(svc, mtime);
|
svc_check_dirty(svc, mtime);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -772,8 +772,9 @@ void service_monitor(pid_t lost)
|
|||||||
|
|
||||||
static void service_retry(svc_t *svc)
|
static void service_retry(svc_t *svc)
|
||||||
{
|
{
|
||||||
int *restart_counter = (int *)&svc->restart_counter;
|
|
||||||
int timeout;
|
int timeout;
|
||||||
|
int *restart_counter = (int *)&svc->restart_counter;
|
||||||
|
|
||||||
service_timeout_cancel(svc);
|
service_timeout_cancel(svc);
|
||||||
|
|
||||||
if (svc->state != SVC_HALTED_STATE ||
|
if (svc->state != SVC_HALTED_STATE ||
|
||||||
@@ -785,7 +786,7 @@ static void service_retry(svc_t *svc)
|
|||||||
|
|
||||||
if (*restart_counter >= RESPAWN_MAX) {
|
if (*restart_counter >= RESPAWN_MAX) {
|
||||||
_e("%s keeps crashing, not restarting", svc->desc);
|
_e("%s keeps crashing, not restarting", svc->desc);
|
||||||
svc->block = SVC_BLOCK_CRASHING;
|
svc_crashing(svc);
|
||||||
*restart_counter = 0;
|
*restart_counter = 0;
|
||||||
service_step(svc);
|
service_step(svc);
|
||||||
return;
|
return;
|
||||||
@@ -793,16 +794,13 @@ static void service_retry(svc_t *svc)
|
|||||||
|
|
||||||
(*restart_counter)++;
|
(*restart_counter)++;
|
||||||
|
|
||||||
_d("%s crashed, trying to start it again, attempt %d",
|
_d("%s crashed, trying to start it again, attempt %d", svc->desc, *restart_counter);
|
||||||
svc->desc, *restart_counter);
|
svc_unblock(svc);
|
||||||
|
|
||||||
svc->block = SVC_BLOCK_NONE;
|
|
||||||
service_step(svc);
|
service_step(svc);
|
||||||
|
|
||||||
/* Wait 2s for the first 5 respawns, then back off to 5s */
|
/* Wait 2s for the first 5 respawns, then back off to 5s */
|
||||||
timeout = ((*restart_counter) <= (RESPAWN_MAX / 2)) ? 2000 : 5000;
|
timeout = ((*restart_counter) <= (RESPAWN_MAX / 2)) ? 2000 : 5000;
|
||||||
service_timeout_after(svc, timeout, service_retry);
|
service_timeout_after(svc, timeout, service_retry);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void svc_set_state(svc_t *svc, svc_state_t new)
|
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)
|
void service_step(svc_t *svc)
|
||||||
{
|
{
|
||||||
/* These fields are marked as const in svc_t, only this
|
int err;
|
||||||
* function is allowed to modify them */
|
|
||||||
int *restart_counter = (int *)&svc->restart_counter;
|
int *restart_counter = (int *)&svc->restart_counter;
|
||||||
|
|
||||||
svc_cmd_t enabled;
|
svc_cmd_t enabled;
|
||||||
svc_state_t old_state;
|
svc_state_t old_state;
|
||||||
cond_state_t cond;
|
cond_state_t cond;
|
||||||
int err;
|
|
||||||
|
|
||||||
restart:
|
restart:
|
||||||
old_state = svc->state;
|
old_state = svc->state;
|
||||||
@@ -837,7 +832,7 @@ restart:
|
|||||||
svc_status(svc), enabled ? "en" : "dis", svc_dirtystr(svc),
|
svc_status(svc), enabled ? "en" : "dis", svc_dirtystr(svc),
|
||||||
condstr(cond_get_agg(svc->cond)));
|
condstr(cond_get_agg(svc->cond)));
|
||||||
|
|
||||||
switch(svc->state) {
|
switch (svc->state) {
|
||||||
case SVC_HALTED_STATE:
|
case SVC_HALTED_STATE:
|
||||||
if (enabled)
|
if (enabled)
|
||||||
svc_set_state(svc, SVC_READY_STATE);
|
svc_set_state(svc, SVC_READY_STATE);
|
||||||
@@ -846,7 +841,7 @@ restart:
|
|||||||
case SVC_DONE_STATE:
|
case SVC_DONE_STATE:
|
||||||
#ifndef INETD_DISABLED
|
#ifndef INETD_DISABLED
|
||||||
if (svc_is_inetd_conn(svc)) {
|
if (svc_is_inetd_conn(svc)) {
|
||||||
if (svc_is_busy(svc)) {
|
if (svc_is_busy(svc->inetd.svc)) {
|
||||||
svc_unblock(svc->inetd.svc);
|
svc_unblock(svc->inetd.svc);
|
||||||
service_step(svc->inetd.svc);
|
service_step(svc->inetd.svc);
|
||||||
}
|
}
|
||||||
@@ -899,23 +894,7 @@ restart:
|
|||||||
}
|
}
|
||||||
|
|
||||||
svc_mark_clean(svc);
|
svc_mark_clean(svc);
|
||||||
|
svc_set_state(svc, SVC_RUNNING_STATE);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -926,15 +905,25 @@ restart:
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!svc->pid && !svc_is_inetd(svc)) {
|
if (!svc->pid) {
|
||||||
svc->block = SVC_BLOCK_RESTARTING;
|
if (svc_is_daemon(svc)) {
|
||||||
svc_set_state(svc, SVC_HALTED_STATE);
|
svc_restarting(svc);
|
||||||
|
svc_set_state(svc, SVC_HALTED_STATE);
|
||||||
|
|
||||||
/* Restart directly after the first crash,
|
/*
|
||||||
* then retry after 2s. */
|
* Restart directly after the first crash,
|
||||||
_d("delayed restart of %s", svc->desc);
|
* then retry after 2 sec
|
||||||
service_timeout_after(svc, 1, service_retry);
|
*/
|
||||||
break;
|
_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);
|
cond = cond_get_agg(svc->cond);
|
||||||
@@ -1007,35 +996,9 @@ restart:
|
|||||||
|
|
||||||
void service_step_all(int types)
|
void service_step_all(int types)
|
||||||
{
|
{
|
||||||
svc_t *svc;
|
svc_foreach_type(types, service_step);
|
||||||
|
|
||||||
for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) {
|
|
||||||
if (!(svc->type & types))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
service_step(svc);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#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:
|
* Local Variables:
|
||||||
* indent-tabs-mode: t
|
* indent-tabs-mode: t
|
||||||
|
|||||||
@@ -34,10 +34,8 @@ int service_enabled (svc_t *svc);
|
|||||||
|
|
||||||
void service_reload_dynamic (void);
|
void service_reload_dynamic (void);
|
||||||
|
|
||||||
void service_step(svc_t *svc);
|
void service_step (svc_t *svc);
|
||||||
void service_step_all(int types);
|
void service_step_all (int types);
|
||||||
|
|
||||||
int service_stop_is_done(void);
|
|
||||||
|
|
||||||
#endif /* FINIT_SERVICE_H_ */
|
#endif /* FINIT_SERVICE_H_ */
|
||||||
|
|
||||||
|
|||||||
@@ -64,7 +64,7 @@
|
|||||||
* Finit currently forwards this to SIGUSR2.
|
* Finit currently forwards this to SIGUSR2.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sched.h>
|
#include <dirent.h>
|
||||||
#include <string.h> /* strerror() */
|
#include <string.h> /* strerror() */
|
||||||
#include <sys/reboot.h>
|
#include <sys/reboot.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
@@ -80,16 +80,64 @@
|
|||||||
#include "service.h"
|
#include "service.h"
|
||||||
#include "utmp-api.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 int stopped = 0;
|
||||||
static uev_t sigterm_watcher, sigusr1_watcher, sigusr2_watcher;
|
static uev_t sigterm_watcher, sigusr1_watcher, sigusr2_watcher;
|
||||||
static uev_t sighup_watcher, sigint_watcher, sigpwr_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;
|
static uev_t sigstop_watcher, sigtstp_watcher, sigcont_watcher;
|
||||||
|
|
||||||
void mdadm_wait(void);
|
void mdadm_wait(void);
|
||||||
void unmount_tmpfs(void);
|
void unmount_tmpfs(void);
|
||||||
void unmount_regular(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)
|
void do_shutdown(shutop_t op)
|
||||||
{
|
{
|
||||||
@@ -98,30 +146,16 @@ void do_shutdown(shutop_t op)
|
|||||||
if (sdown)
|
if (sdown)
|
||||||
run_interactive(sdown, "Calling shutdown hook: %s", 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 */
|
/* Update UTMP db */
|
||||||
utmp_set_halt();
|
utmp_set_halt();
|
||||||
|
|
||||||
/* Here is where we signal watchdogd to do a forced reset for us */
|
/*
|
||||||
_d("Sending SIGTERM to all processes");
|
* Tell all remaining non-monitored processes to exit, give them
|
||||||
kill(-1, SIGTERM);
|
* some time to exit gracefully, 2 sec is customary.
|
||||||
|
*/
|
||||||
/* Wait for WDT to timeout, should be no more than ~1 sec. */
|
do_kill(SIGTERM);
|
||||||
do_sleep(2);
|
do_sleep(2);
|
||||||
|
do_kill(SIGKILL);
|
||||||
_d("Sending SIGKILL to remaining processes");
|
|
||||||
kill(-1, SIGKILL);
|
|
||||||
|
|
||||||
/* Exit plugins and API gracefully */
|
/* Exit plugins and API gracefully */
|
||||||
plugin_exit();
|
plugin_exit();
|
||||||
@@ -152,6 +186,7 @@ void do_shutdown(shutop_t op)
|
|||||||
unmount_regular();
|
unmount_regular();
|
||||||
|
|
||||||
/* We sit on / so we must remount it ro, try all the things! */
|
/* 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 -t dummytype dummydev /");
|
||||||
run("/bin/mount -n -o remount,ro dummydev /");
|
run("/bin/mount -n -o remount,ro dummydev /");
|
||||||
run("/bin/mount -n -o remount,ro /");
|
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. */
|
/* Call mdadm to mark any RAID array(s) as clean before halting. */
|
||||||
mdadm_wait();
|
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");
|
_d("%s", op == SHUT_REBOOT ? "Rebooting" : "Halting");
|
||||||
if (op == SHUT_REBOOT)
|
if (op == SHUT_REBOOT)
|
||||||
reboot(RB_AUTOBOOT);
|
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))
|
static void sighup_cb(uev_t *UNUSED(w), void *UNUSED(arg), int UNUSED(events))
|
||||||
{
|
{
|
||||||
|
_d("...");
|
||||||
/* INIT_CMD_RELOAD: 'init q', 'initctl reload', and SIGHUP */
|
/* INIT_CMD_RELOAD: 'init q', 'initctl reload', and SIGHUP */
|
||||||
service_reload_dynamic();
|
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))
|
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))
|
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))
|
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))
|
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);
|
} 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
|
* 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 */
|
/* After initial bootstrap of Finit we call the service monitor to reap children */
|
||||||
uev_signal_init(ctx, &sigchld_watcher, sigchld_cb, NULL, SIGCHLD);
|
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. */
|
/* Stopping init is a bit tricky. */
|
||||||
uev_signal_init(ctx, &sigstop_watcher, sigstop_cb, NULL, SIGSTOP);
|
uev_signal_init(ctx, &sigstop_watcher, sigstop_cb, NULL, SIGSTOP);
|
||||||
uev_signal_init(ctx, &sigtstp_watcher, sigstop_cb, NULL, SIGTSTP);
|
uev_signal_init(ctx, &sigtstp_watcher, sigstop_cb, NULL, SIGTSTP);
|
||||||
|
|||||||
@@ -66,6 +66,8 @@ typedef enum {
|
|||||||
SHUT_REBOOT
|
SHUT_REBOOT
|
||||||
} shutop_t;
|
} shutop_t;
|
||||||
|
|
||||||
|
extern shutop_t halt;
|
||||||
|
|
||||||
void do_shutdown (shutop_t op);
|
void do_shutdown (shutop_t op);
|
||||||
int sig_stopped (void);
|
int sig_stopped (void);
|
||||||
void sig_init (void);
|
void sig_init (void);
|
||||||
|
|||||||
@@ -127,6 +127,12 @@ restart:
|
|||||||
_d("Setting new runlevel --> %d <-- previous %d", runlevel, prevlevel);
|
_d("Setting new runlevel --> %d <-- previous %d", runlevel, prevlevel);
|
||||||
runlevel_set(prevlevel, runlevel);
|
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/ */
|
/* Make sure to (re)load all *.conf in /etc/finit.d/ */
|
||||||
conf_reload_dynamic();
|
conf_reload_dynamic();
|
||||||
|
|
||||||
@@ -140,7 +146,7 @@ restart:
|
|||||||
case SM_RUNLEVEL_WAIT_STATE:
|
case SM_RUNLEVEL_WAIT_STATE:
|
||||||
/* Need to wait for any services to stop? If so, exit early
|
/* Need to wait for any services to stop? If so, exit early
|
||||||
* and perform second stage from service_monitor later. */
|
* and perform second stage from service_monitor later. */
|
||||||
if (!service_stop_is_done())
|
if (!svc_stop_completed())
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* Prev runlevel services stopped, call hooks before starting new runlevel ... */
|
/* Prev runlevel services stopped, call hooks before starting new runlevel ... */
|
||||||
@@ -154,19 +160,14 @@ restart:
|
|||||||
/* Cleanup stale services */
|
/* Cleanup stale services */
|
||||||
svc_clean_dynamic(service_unregister);
|
svc_clean_dynamic(service_unregister);
|
||||||
|
|
||||||
/* Disable login in single-user mode as well as shutdown/reboot */
|
/*
|
||||||
if (runlevel == 1 || runlevel == 0 || runlevel == 6)
|
* "I've seen things you people wouldn't believe. Attack ships on fire off
|
||||||
touch("/etc/nologin");
|
* the shoulder of Orion. I watched C-beams glitter in the dark near the
|
||||||
else
|
* Tannhäuser Gate. All those .. moments .. will be lost in time, like
|
||||||
erase("/etc/nologin");
|
* tears ... in ... rain."
|
||||||
|
*/
|
||||||
if (0 == runlevel) {
|
if (runlevel == 0 || runlevel == 6) {
|
||||||
do_shutdown(SHUT_OFF);
|
do_shutdown(halt);
|
||||||
sm->state = SM_RUNNING_STATE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (6 == runlevel) {
|
|
||||||
do_shutdown(SHUT_REBOOT);
|
|
||||||
sm->state = SM_RUNNING_STATE;
|
sm->state = SM_RUNNING_STATE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -195,7 +196,7 @@ restart:
|
|||||||
case SM_RELOAD_WAIT_STATE:
|
case SM_RELOAD_WAIT_STATE:
|
||||||
/* Need to wait for any services to stop? If so, exit early
|
/* Need to wait for any services to stop? If so, exit early
|
||||||
* and perform second stage from service_monitor later. */
|
* and perform second stage from service_monitor later. */
|
||||||
if (!service_stop_is_done())
|
if (!svc_stop_completed())
|
||||||
break;
|
break;
|
||||||
|
|
||||||
sm->in_teardown = 0;
|
sm->in_teardown = 0;
|
||||||
|
|||||||
@@ -24,7 +24,6 @@
|
|||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <strings.h>
|
#include <strings.h>
|
||||||
#include <lite/lite.h>
|
|
||||||
|
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
#include "svc.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
|
* svc_find - Find a service object by its full path name
|
||||||
* @cmd: Full path name, e.g., /sbin/syslogd
|
* @cmd: Full path name, e.g., /sbin/syslogd
|
||||||
@@ -441,7 +478,7 @@ char *svc_status(svc_t *svc)
|
|||||||
case SVC_BLOCK_USER:
|
case SVC_BLOCK_USER:
|
||||||
return "blocked";
|
return "blocked";
|
||||||
|
|
||||||
case SVC_BLOCK_INETD_BUSY:
|
case SVC_BLOCK_BUSY:
|
||||||
return "busy";
|
return "busy";
|
||||||
|
|
||||||
case SVC_BLOCK_RESTARTING:
|
case SVC_BLOCK_RESTARTING:
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ typedef enum {
|
|||||||
SVC_BLOCK_MISSING,
|
SVC_BLOCK_MISSING,
|
||||||
SVC_BLOCK_CRASHING,
|
SVC_BLOCK_CRASHING,
|
||||||
SVC_BLOCK_USER,
|
SVC_BLOCK_USER,
|
||||||
SVC_BLOCK_INETD_BUSY,
|
SVC_BLOCK_BUSY,
|
||||||
SVC_BLOCK_RESTARTING,
|
SVC_BLOCK_RESTARTING,
|
||||||
} svc_block_t;
|
} svc_block_t;
|
||||||
|
|
||||||
@@ -114,8 +114,10 @@ typedef struct svc {
|
|||||||
char args[MAX_NUM_SVC_ARGS][MAX_ARG_LEN];
|
char args[MAX_NUM_SVC_ARGS][MAX_ARG_LEN];
|
||||||
char desc[MAX_STR_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;
|
uev_t timer;
|
||||||
void (*timer_cb)(struct svc *svc);
|
void (*timer_cb)(struct svc *svc);
|
||||||
} svc_t;
|
} 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 (void (*cb)(svc_t *));
|
||||||
void svc_foreach_dynamic (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_mark_dynamic (void);
|
||||||
void svc_check_dirty (svc_t *svc, time_t mtime);
|
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_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_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_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_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_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; }
|
static inline void svc_crashing (svc_t *svc) { svc->block = SVC_BLOCK_CRASHING; }
|
||||||
|
|
||||||
#endif /* FINIT_SVC_H_ */
|
#endif /* FINIT_SVC_H_ */
|
||||||
|
|||||||
@@ -23,6 +23,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <sys/types.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <lite/lite.h>
|
#include <lite/lite.h>
|
||||||
|
|
||||||
@@ -33,7 +35,10 @@
|
|||||||
#include "tty.h"
|
#include "tty.h"
|
||||||
#include "utmp-api.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] */
|
/* tty [!1-9,S] <DEV> [BAUD[,BAUD,...]] [TERM] */
|
||||||
@@ -118,6 +123,19 @@ size_t tty_num(void)
|
|||||||
return num;
|
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 *tty_find_by_pid(pid_t pid)
|
||||||
{
|
{
|
||||||
tty_node_t *entry;
|
tty_node_t *entry;
|
||||||
@@ -195,13 +213,56 @@ int tty_enabled(finit_tty_t *tty, int runlevel)
|
|||||||
return 0;
|
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)
|
int tty_respawn(pid_t pid)
|
||||||
{
|
{
|
||||||
tty_node_t *entry = tty_find_by_pid(pid);
|
tty_node_t *entry = tty_find_by_pid(pid);
|
||||||
|
|
||||||
if (!entry)
|
if (!entry)
|
||||||
return 0;
|
return tty_fallback(pid);
|
||||||
|
|
||||||
/* Set DEAD_PROCESS UTMP entry */
|
/* Set DEAD_PROCESS UTMP entry */
|
||||||
utmp_set_dead(pid);
|
utmp_set_dead(pid);
|
||||||
@@ -228,6 +289,9 @@ void tty_runlevel(int runlevel)
|
|||||||
else
|
else
|
||||||
tty_start(&entry->data);
|
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);
|
int tty_register (char *line);
|
||||||
tty_node_t *tty_find (char *dev);
|
tty_node_t *tty_find (char *dev);
|
||||||
size_t tty_num (void);
|
size_t tty_num (void);
|
||||||
|
size_t tty_num_active (void);
|
||||||
tty_node_t *tty_find_by_pid (pid_t pid);
|
tty_node_t *tty_find_by_pid (pid_t pid);
|
||||||
void tty_start (finit_tty_t *tty);
|
void tty_start (finit_tty_t *tty);
|
||||||
void tty_stop (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.
|
* 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 (int type, int pid, char *line, char *id, char *user);
|
||||||
int utmp_set_boot (void);
|
int utmp_set_boot (void);
|
||||||
int utmp_set_halt (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_set_runlevel(int pre, int now);
|
||||||
int utmp_show (char *file);
|
int utmp_show (char *file);
|
||||||
|
|
||||||
|
#endif /* FINIT_UTMP_API_H_ */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Local Variables:
|
* Local Variables:
|
||||||
* indent-tabs-mode: t
|
* 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