Compare commits

...
90 Commits
Author SHA1 Message Date
Joachim Nilsson 83915b42f3 Bump version for 3.0-rc2, second pre-release
All known major issues triaged or fixed.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-12-09 01:03:18 +01:00
Joachim Nilsson babcd117b1 Fix #43: Add TODO for optimizing HTTP/HTTPS inetd redirect
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-12-09 00:56:39 +01:00
Joachim Nilsson 892ac2edb2 Fix #47: Relocate sysctl.conf setup to procps plugin
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-12-08 08:17:38 +01:00
Joachim Nilsson 5b12d17b56 Fix #52: Add implicit "initctl reload" adter run-parts and rc.local
This patch (untested) patch calls `service_reload_dynamic()` after both
run-parts (if directory exists) and after `/etc/rc.local` has run.  The
intention is to reload any services modified/added/removed by a user
script so the system is properly up to date.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-12-08 01:43:32 +01:00
Joachim Nilsson 1b6930126e Fix #50: Reset TTY properly in stty()
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-12-08 01:38:05 +01:00
Joachim Nilsson 8def97a465 Add missing ctype.h header for whitespace stripper
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-12-08 01:37:56 +01:00
Joachim Nilsson 7bbc0847b1 Unblock udp/wait parent inetd service on child exit
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-12-07 23:31:54 +01:00
Joachim Nilsson 88dc3f0061 Strip leading whitespace from service -- description
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-12-07 22:09:51 +01:00
Joachim Nilsson 02e69932ae Fix inetd regression introduced in 10b72f1
This patch allows all services to go from READY -> RUNNING, this to
prevent started inetd connections from being treated as "stubborn"
and inadvertently killing them off after a few seconds.

The same actually applies to run/task applications.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-12-07 21:51:54 +01:00
Joachim Nilsson 662dfbe777 Travis-CI: Update libuEv build dependency
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-12-05 08:43:48 +01:00
Joachim Nilsson c249cbdbe1 Remove duplicate header
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-12-05 08:40:29 +01:00
Joachim Nilsson a47171891f fixup! Make blocked state more generic
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-12-05 08:40:07 +01:00
Joachim Nilsson 1dc67acd40 chargen: Make sure to check target buffer size
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-12-05 08:37:41 +01:00
Joachim Nilsson 146685c2c2 Fix inverted --enable-quiet option
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-12-03 06:15:46 +01:00
Joachim Nilsson 3cc2df20f9 Update minimum libuev requirement, v1.5.2
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-11-27 20:39:36 +01:00
Joachim Nilsson 4f3d246100 Make blocked state more generic
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-11-27 20:38:50 +01:00
Joachim Nilsson 11bfec1a23 Add missing header include guards
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-11-27 17:38:39 +01:00
Joachim Nilsson f24a03a32c Refactor little progname() for all applictions
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-11-27 17:38:01 +01:00
Joachim Nilsson 829ff0b9f7 Fix #51: Catching SIGSEGV not needed anymore
This patch fixes issue #51 by reverting b4b63d3, which is not needed
anymore since service callbacks have been removed from Finit3.

The `sig_unblock()` function, called for each forked off child, should
now be balanced with caught signals.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-11-27 17:28:15 +01:00
Joachim Nilsson b9ae4d04ef bootmisc: Replace homegrown desym() with realpath()
Followup to issue #49.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-11-21 15:01:59 +01:00
Joachim Nilsson 47060c9738 bootclean: Resolve any symlinks in tmpfs check
Followup to issue #49.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-11-21 09:41:30 +01:00
Joachim Nilsson 846692ca03 Fix #49: Skip tmpfs directories at bootclean
We can safely skip tmpfs, nothing to clean from previous boot there.
In fact, if we clean it we may spoil things for udev, which saves
pre-boot files in /run/udev.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-11-20 19:29:42 +01:00
Joachim Nilsson 985d53bec4 Restore "udevadm settle" from 8f05b36, see #49
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-11-20 19:29:42 +01:00
Joachim Nilsson 8548e67dcd Update install warning text slightly.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-11-20 19:29:42 +01:00
Joachim Nilsson 1c60e949e7 Fix regression from bc84d66 preventing cond_update(NULL)
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-11-18 13:32:55 +01:00
Wang He 86f02e8553 Fix ordering bug, progname() must be called before translate()
Signed-off-by: Wang He <xw897002528@gmail.com>
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-11-12 16:51:29 +01:00
Joachim Nilsson 2c7332583c reboot: Fix build problem after prognm refactor.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-11-12 13:46:50 +01:00
Joachim Nilsson a96b74ea5e reboot: Replace __progname with a small function
This patch removes the use of non-standard __progname and replaces it
with a small function.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-11-11 21:28:19 +01:00
Joachim Nilsson 5a1b13ff41 Improve initctl show SVC output
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-11-11 21:27:08 +01:00
Joachim Nilsson 4a71f19c40 Code cleanup and improved svc abstraction
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-11-01 16:00:20 +01:00
Joachim Nilsson 5c672885f1 Minor cleanup of README, comments, and whitespace
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-10-31 19:07:43 +01:00
Joachim Nilsson e38eb7cbd5 Minor: relocate code to get rid of #ifdefs
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-10-24 00:25:58 +02:00
Joachim Nilsson ba9ae0337d TODO: Good enough watchdog implementation now in place
This patch removes the long standing Watchdog daemon from the TODO list.
We now have a bare-bones watchdog service built-in to Finit, with
support for handing over to an external, and possibly more advanced,
using the initctl API.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-10-24 00:08:58 +02:00
Joachim Nilsson b674aad802 watchdog: Add simple built-in watchdog daemon
This patch adds a simple but effective watchdog daemon with support for
handover to an external daemon, should one register using the API.

Disabled by default, enable by:

    configure --enable-watchdog

The watchdog forks to the background, opening /dev/watchdog setting a
three second timeout, and kicking every second.  At shutdown/reboot the
daemon will receive SIGPWR from Finit to exit and cause a WDT reboot.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-10-24 00:06:04 +02:00
Joachim Nilsson 88f9458c6e reboot: Wait a bit on successful signal delivery
To prevent returning the prompt too soon, and thereby messing up the
output from Finit, wait a bit after successful delivery of signal to
reboot/halt/poweroff.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-10-24 00:02:19 +02:00
Joachim Nilsson 6cb3d86cd1 Add support for registering a watchdog daemon
This patch adds initial support for registering a watchdog daemon with
Finit.  Needed for situations when you want the system to actually be
rebooted by the watchdog timer (WDT) circuitry rather than the kernel.

The initctl API has been extended with a INIT_CMD_WDOG_HELLO command
that is used to both register and "ping" Finit periodically.  As long as
Finit responds (with an ACK) the watchdog daemon knows Finit is alive.

At shutdown Finit stops all services (except kernel threads and daemons
marked with @ in the first character of their process name) and, if a
watchdog has registered, SIGPWR is sent to it when Finit has finished
unmounting etc., just prior to kernel reboot/halt/poweroff.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-10-24 00:02:19 +02:00
Joachim Nilsson 5cde809909 Add debug messages to signal handlers
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-10-24 00:02:19 +02:00
Joachim Nilsson 1b6931eaea Protect API socket from unauthorized access
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-10-24 00:02:19 +02:00
Joachim Nilsson c3b7530b98 Reenable terse mode at shutdown/reboot
Now that we change runlevel at shutdown/reboot, we also need to restore
terse mode before calling the shutdown hooks, like before.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-10-24 00:02:18 +02:00
Joachim Nilsson 0f61b0792b Minor cleanup
No need to assign result = 0 since that is the default, also
no other case sets result to OK.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-10-23 13:10:20 +02:00
Joachim Nilsson bab13c9cef bootclean: Followup to a013e48, reduced verbosity
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-10-23 11:28:24 +02:00
Joachim Nilsson 9c9fe51eee Fine grained signaling of processes at shutdown
This patch replaces kill(-1, signo) with a more fine grained
do_kill(signo) that traverses each /proc/PID, skipping kernel
threads and special [0][0] == '@' processes.

The reason for this patch is not only future compliance with
freedesktop.org standards, but also a way of not killing any
critical processes at shutdown, e.g. mdadm or watchdogd.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-10-23 00:28:41 +02:00
Joachim Nilsson 4f8211f6a1 Beautify 'mount -a' error message at boot
This patch from TroglOS makes sure to print any error message from mount
after [FAIL] is printed.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-10-22 18:36:51 +02:00
Joachim Nilsson 5fc3a0a3b9 Move HOOK_SHUTDOWN so it runs right before runlevel change
The shutdown hook is supposed to run right before services start
receiving SIGTERM.  Change due to previous refactor.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-10-16 23:06:17 +02:00
Joachim Nilsson 67c55145b9 Fix warning for comment in comment
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-10-10 00:03:08 +02:00
Joachim Nilsson fc2489d9e1 Remove or mark unused variables
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-10-10 00:02:45 +02:00
Joachim Nilsson a384a95529 Add missing warning flags and enable STD:GNU99
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-10-10 00:02:10 +02:00
Joachim Nilsson a013e48ab5 Run bootclean() from bootmisc plugin instead
This patch moves both the definition and the call to bootclean() from
finit.c to the bootmisc plugin.  We want to call bootclean() *after*
any /run and /var file systems have been mounted.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-10-09 23:15:06 +02:00
Joachim Nilsson 24a0ddfc59 Minor, remove TODO comment, fixed now.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-10-06 23:07:07 +02:00
Joachim Nilsson 3da4c2abe9 README: Add requirements to ToC
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-10-05 23:16:09 +02:00
Joachim Nilsson 2950820d34 README: Add requirements section
- New requirements section about what Finit expects from the system
- Remove commented out `udevadm settle` code, now in README

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-10-05 23:14:21 +02:00
Joachim Nilsson 75b1ac8199 Fix CID 171497, ignore return value from remove()
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-10-04 12:37:36 +02:00
Joachim Nilsson 8f05b36551 Do not call udevadm settle, only Debian uses this
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-10-04 12:12:59 +02:00
Joachim Nilsson 0f840e6576 Do not force silent mode on udev systems
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-10-04 12:12:59 +02:00
Joachim Nilsson 451f63ebe0 Clean up unused local variables
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-10-02 23:11:49 +02:00
Joachim Nilsson 2dc9daf118 Clear screen in silent mode
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-10-02 23:10:49 +02:00
Joachim Nilsson 3c67a10347 Actually unblock signals for child processes
Also, make them session leader so they can manage their own offspring if
needed.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-10-02 23:08:39 +02:00
Joachim Nilsson 6885a9f868 Systems with udev/udevadm mess up /dev/console => silence console
On systems with systemd-udev/udevadm the trigger addition of devices at
boot wrecks havoc of /dev/console.  This patch forces Finit to go silent
by default on such systems.  Far from ideal, but since the actual root
cause for this messup is unknown this will have to do for now.

Also, add a settle timeout of 120 sec to the udev device tree population.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-10-02 23:08:18 +02:00
Joachim Nilsson 38142baa93 Do not fork external process, use sync(2) instead
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-10-02 14:06:06 +02:00
Joachim Nilsson 34bdbdb3b1 resolvconf: Simplify and fix buglet
- The /dev/shm/ directories are no longer needed
- Do not create the resolv.conf symlink

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-10-02 13:14:16 +02:00
Joachim Nilsson 83af7e8e9d resolvconf: Initial cleanup of plugin
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-10-02 13:06:03 +02:00
Joachim Nilsson 4eb5f8a0dc bootmisc: /var/lock/subsys created by D-Bus plugin
No need to create it twice.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-10-02 12:05:27 +02:00
Joachim Nilsson e03b358ff0 Fix #46: Set correct umask() before makedir() and chmod()
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-10-02 11:42:40 +02:00
Wang He d2846b805a Fix issue #42: Skip base directories in bootclean.
Signed-off-by: Wang He <xw897002528@gmail.com>
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-10-02 11:07:54 +02:00
Joachim Nilsson 07d767e1af Fix issue #42: Use ftw() to recursively clean up dirs.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-09-30 23:01:26 +02:00
Joachim Nilsson d423e6b774 doc: Reminder about conditions for run/task/service/inetd
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-09-26 21:43:56 +02:00
Joachim Nilsson bb89bdd8a9 Refactor fallback handling in getent()
This patch factors out the fgetint() fallback code for parsing
/etc/services and /etc/protocols.  Useful on systems with a
malfunctioning C library.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-09-26 21:42:34 +02:00
Joachim Nilsson 5cc98f6e53 inetd: List service/proto in error message
Improve error when failing to register an inetd service.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-09-26 21:41:28 +02:00
Joachim Nilsson a6300f6ac6 Fix warning on 32-bit ARM: 2 << 31 overflows int
Thanks to GCC 6.1 for finding this.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-09-26 21:40:31 +02:00
Joachim Nilsson aeabb4d2ea Realign logo and mention systemd
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-09-21 15:40:27 +02:00
Joachim Nilsson dcbb429863 Remove logo HTML+CSS alignment screws up rendering
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-09-21 15:11:14 +02:00
Joachim Nilsson 077d52d209 Attempt new right-floating logo
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-09-21 15:09:55 +02:00
Joachim Nilsson 44f5de188d Update screenshot to Finit3
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-09-18 19:04:55 +02:00
Joachim Nilsson 191e5440b2 tty.c: Fix minor regression from f9732a6
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-09-18 18:52:56 +02:00
Joachim Nilsson a2b0d00058 reboot: Add poweroff symlink, now also supported
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-09-18 18:32:53 +02:00
Joachim Nilsson e8fa827026 README: Further cleanup and refactoring
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-09-18 18:32:38 +02:00
Joachim Nilsson 89105090ed Massive update, cleanup of README
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-09-18 16:53:20 +02:00
Joachim Nilsson 6ce218612b Fix build warnings if fallback shell is disabled
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-09-18 12:11:07 +02:00
Wang He dd87c81adc Create missing /var/lock/subsys dir in dbus plugin
Signed-off-by: Wang He <xw897002528@gmail.com>
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-09-18 12:09:05 +02:00
Wang He 37f3478873 Run udev triggers to add subsystems and devices
Without trigger, kernel modules won't be loaded automatically.  Also
devices are not managed.  For example, i915 was not loaded after boot
and my network card was not renamed from wlan0 to wlp3s0, which means
it was not handled properly by udev.

Signed-off-by: Wang He <xw897002528@gmail.com>
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-09-18 12:06:12 +02:00
Wang He a64259362e Clean up hidden dot files from /tmp
Signed-off-by: Wang He <xw897002528@gmail.com>
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-09-18 12:02:36 +02:00
Wang He 3554138118 Sync needed before remount R/O
Signed-off-by: Wang He <xw897002528@gmail.com>
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-09-18 12:00:16 +02:00
Joachim Nilsson f7d6d269c7 Change to runlevel 0/6 on reboot/halt/poweroff
This patch fixes a long-standing issue with how Finit handles shutdown,
reboot and poweroff -- and even runlevel changes to runlevel 0 and 6.

Prior to this patch sig.c:do_shutdown() was called immediately on any
of the above events, disregarding any services that a user might have
wanted to run as part of the shutdown/reboot.

With this change the handling is unified in all frontends to instead
do a runlevel change followed by the do_shutdown() action.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-09-18 11:50:07 +02:00
Joachim Nilsson 2c1e9877f9 Touch /etc/nologin when runlevel change comes in
The /etc/nologin file must be set as soon as the runlevel change to
0/1/6 comes in, not when done with runlevel change and services have
been started, if any.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-09-18 11:24:10 +02:00
Joachim Nilsson a94c97221e Force all log messages to console in --debug mode
As a last ditch effort to understand why an embedded system doesn't
boot, the operator should be able to see as much logs as possible
when enabling --debug mode on the kernel command line.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-09-18 10:27:03 +02:00
Joachim Nilsson f9732a6fb9 Fix warnings: type mismatch and unused parameters
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-09-18 10:27:03 +02:00
Joachim Nilsson 581fc956be Staticify local variable
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-09-18 10:27:03 +02:00
Joachim Nilsson ee901b018c Finit bringup: add optional fallback shell
This patch adds an `--enable-fallback-shell` option to confiugre.
When enabled Finit will start `/bin/sh` on the console, but only
if there are no active TTYs running in the current runlevel.

With this it will be easier to do board bringup with Finit, but it also
enables using the fallback shell in a rescue mode (runlevel) where no
TTYs are allowed to run.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-09-18 10:27:03 +02:00
Joachim Nilsson d373ebfdd7 New function tty_num_active()
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-09-17 22:52:21 +02:00
Joachim Nilsson 698b87dd35 Clean out remnants of old (now unused) fallback shell
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-09-17 21:09:45 +02:00
48 changed files with 1086 additions and 500 deletions
+3 -3
View File
@@ -33,11 +33,11 @@ addons:
branch_pattern: dev
install:
- wget https://github.com/troglobit/libuev/releases/download/v1.4.2/libuev-1.4.2.tar.xz
- wget https://github.com/troglobit/libuev/releases/download/v1.5.2/libuev-1.5.2.tar.xz
- wget https://github.com/troglobit/libite/releases/download/v1.8.2/libite-1.8.2.tar.xz
- tar xf libuev-1.4.2.tar.xz
- tar xf libuev-1.5.2.tar.xz
- tar xf libite-1.8.2.tar.xz
- (cd libuev-1.4.2 && ./configure --prefix=/tmp && make && make install-strip)
- (cd libuev-1.5.2 && ./configure --prefix=/tmp && make && make install-strip)
- (cd libite-1.8.2 && ./configure --prefix=/tmp && make && make install-strip)
# Custom build script for the time being, no "make test" yet
+8 -4
View File
@@ -14,11 +14,15 @@ finit_SOURCES = api.c \
sm.c sm.h \
svc.c svc.h \
tty.c tty.h \
util.c util.h \
utmp-api.c utmp-api.h
pkginclude_HEADERS = cond.h finit.h helpers.h inetd.h plugin.h svc.h
if INETD
finit_SOURCES += inetd.c inetd.h
endif
if WATCHDOGD
finit_SOURCES += watchdog.c watchdog.h
endif
finit_CFLAGS = -W -Wall -Wextra -std=gnu99 $(lite_CFLAGS) $(uev_CFLAGS)
finit_LDADD = $(lite_LIBS) $(uev_LIBS)
@@ -29,14 +33,14 @@ finit_LDADD += -ldl
endif
initctl_SOURCES = initctl.c svc.c svc.h helpers.c helpers.h cond.c cond.h \
utmp-api.c utmp-api.h
util.c util.h utmp-api.c utmp-api.h
initctl_CFLAGS = $(lite_CFLAGS)
initctl_LDADD = $(lite_LIBS)
reboot_SOURCES = reboot.c
reboot_SOURCES = reboot.c util.c util.h
INIT_LNKS = telinit init
REBOOT_LNKS = shutdown halt suspend
REBOOT_LNKS = shutdown halt poweroff suspend
SUBDIRS = plugins
doc_DATA = README.md LICENSE finit.conf
EXTRA_DIST = README.md LICENSE ChangeLog.md finit.conf
@@ -65,7 +69,7 @@ install-exec-hook:
fi; \
done
@if [ -L $(DESTDIR)$(sbindir)/reboot ]; then \
echo "Non-finit reboot, skipping."; \
echo "Non-finit reboot, skipping install."; \
else \
for file in $(REBOOT_LNKS); do \
link=$(DESTDIR)$(sbindir)/$$file; \
+90 -92
View File
@@ -1,19 +1,8 @@
```
_______ __ _____ ___ __ ___________ _______
/" "||" \ (\" \|" \ |" \(" _ ")/" __ )
(: ______)|| | |.\\ \ | || |)__/ \\__/(__/ _) ./
\/ | |: | |: \. \\ | |: | \\_ / / //
// ___) |. | |. \ \. | |. | |. | __ \_ \\
(: ( /\ |\| \ \ | /\ |\ \: | (: \__) :\
\__/ (__\_|_)\___|\____\)(__\_|_) \__| \_______) ... Yes, we need a new logo!
```
Fast init for Linux
===================
[![Travis Status]][Travis] [![Coverity Status]][Coverity Scan]
<p align="center"><img src="images/finit3.png" alt="Finit: Fast Init" /></p>
Table of Contents
-----------------
[![Travis Status]][Travis] [![Coverity Status]][Coverity Scan]
* [Introduction](#introduction)
* [Features](#features)
@@ -27,6 +16,7 @@ Table of Contents
* [Rebooting & Halting](#rebooting--halting)
* [Commands & Status](#commands--status)
* [Building](doc/build.md#building)
* [Requirements](#requirements)
* [Running](#running)
* [Debugging](#debugging)
* [Origin & References](#origin--references)
@@ -35,11 +25,15 @@ Table of Contents
Introduction
------------
Finit is an EeePC inspired Fastinit clone with [process supervision][1]
Finit is an EeePC Fastinit inspired clone with [process supervision][1]
similar to that of D.J. Bernstein's [daemontools][2] and Gerrit Pape's
[runit][3]. The focus of Finit is on small and embedded Linux systems,
although it is fully usable on server and desktop installations as well.
See the [contrib section](contrib/) for Debian and Alpine examples.
[runit][3]. It also supports free-form conditions based on events, e.g.
triggering on PID file creation, Netlink events like a default route or
interfaces coming up, or even custom events. Similar to [systemd][6].
Finit focuses on small and embedded Linux systems, although fully usable
on servers and desktops as well. See the [contrib section](contrib/)
for Debian and Alpine Linux examples.
Traditional [SysV init][4] style systems are scripted. For low-resource
embedded systems this is quite resource intensive and often leads to
@@ -140,26 +134,26 @@ nasty bits with PAM etc.
**Runlevels**
Runlevels are optional in Finit, but support for [SysV runlevels][5] is
available if needed. All services in runlevel S(1) are started first,
followed by the desired run-time runlevel. Runlevel S can be started in
sequence by using `run [S] cmd`. Changing runlevels at runtime is done
like any other init, e.g. <kbd>init 4</kbd>
Support for SysV init-style [runlevels][5] is available, in the same
minimal style as everything else in Finit. The `[2345]` syntax can be
applied to service, task, run, inetd, and TTY stanzas.
All services in runlevel S(1) are started first, followed by the desired
run-time runlevel. Runlevel S can be started in sequence by using `run
[S] cmd`. Changing runlevels at runtime is done like any other init,
e.g. <kbd>init 4</kbd>, but also using the more advanced `intictl` tool.
**Plugins**
Finit plugins can be *callbacks*, *boot hooks* into different stages of
the boot process, or *pure extensions*. Plugins are written in C and
compiled into a dynamic library that is loaded automatically by finit at
boot. A basic set of plugins that extend and modify the basic behavior
are bundled in the `plugins/` directory.
Plugins can *extend* the functionality of Finit and *hook into* the
different stages of the boot process and at runtime. Plugins are
written in C and compiled into a dynamic library loaded automatically by
finit at boot. A basic set of plugins are bundled in the `plugins/`
directory.
Capabilities:
- **Task/Run/Service callbacks**
Modify service arguments, override service monitor's decisions to
start/stop/reload a service.
- **Hooks**
Hook into the boot at predefined points to extend Finit
- **I/O**
@@ -178,7 +172,7 @@ For more information, see [doc/plugins.md](doc/plugins.md).
Runparts & /etc/rc.local
------------------------
At the end of the boot, when networking and all services are up, finit
At the end of the boot, when networking and all services are up, Finit
calls its built-in [run-parts(8)][] on the `runparts <DIR>` directory,
and `/etc/rc.local`, in that order if they exist.
@@ -210,7 +204,7 @@ are used, and even more commonly, only the default runlevel is used.
To specify an allowed set of runlevels for a `service`, `run` command,
`task`, or `tty`, add `[NNN]` to your `/etc/finit.conf`, like this:
```shell
```
service [S12345] /sbin/syslogd -n -x -- System log daemon
run [S] /etc/init.d/acpid start -- Starting ACPI Daemon
task [S] /etc/init.d/kbd start -- Preparing console
@@ -247,58 +241,36 @@ start any new ones for you, without rebooting the system.
Rebooting & Halting
-------------------
Finit is often used on embedded and small Linux systems with BusyBox.
For compatibility with its existing toolset (halt, poweroff, reboot),
the following signals have been adopted:
Traditionally, rebooting and halting a UNIX system is done by changing
its runlevel. Finit comes with its own tooling providing: `shutdown`,
`reboot`, `poweroff`, and `suspend`, but also the traditional `init` and
`telinit`, as well as a more modern `initctl` tool, detailed in the next
section.
* `SIGUSR1`
Same effect as `finit q`, reloads all *.conf files in `/etc/finit.d/`
* `SIGUSR1`
Calls shutdown hooks, including HOOK_SHUTDOWN, stops all running
processes, and unmounts all file systems. Then tells kernel to
halt. Most people these days want SIGUSR2 though.
For compatibility reasons Finit listens to the same set of signals as
BusyBox init. This is not 100% compatible with SysV init, but clearly
the more common combination for Finit. For more details, see
[doc/signals.md](doc/signals.md).
SysV init and systemd use this to re-open their FIFO/D-Bus.
* `SIGUSR2`
Like SIGUSR1, but tell kernel to power-off the system, if ACPI
or similar exists to actually do this. If the kernel fails
power-off, Finit falls back to halt.
SysV init N/A, systemd dumps its internal state to log.
* `SIGTERM`
Like `SIGUSR1`, but tell kernel to reboot the system when done.
SysV init N/A, systemd rexecutes itself.
* `SIGINT`
Sent from kernel when the CTRL-ALT-DEL key combo is pressed.
SysV init and systemd default to reboot with `shutdown -r`.
Finit currently forwards this to `SIGTERM`.
* `SIGPWR`
Sent from a power daemon, like `powstatd(8)`, on changes to the
UPS status. Traditionally SysV init read /etc/powerstatus and
acted on "OK", "FAIL", or "LOW" and then removed the file.
Finit currently forwards this to `SIGUSR2`.
Finit also listens to the classic SysV init FIFO, used by `telinit`.
Support for this is implemented by the `initctl.so` plugin. Hence,
`telinit q` will work as the UNIX beards intended.
Finit also listens to the classic SysV init FIFO, which used to be
located in `/dev` but these days default to `/run/initctl`. So existing
tools like, `poweroff`, `halt`, `reboot`, and `shutdown` work as
expected. Support for this old-style handling is implemented in the
optional `initctl.so` plugin and can be accessed with the traditional
`telinit` command line tool, symlinked to `finit`. Hence, if finit is
your system init, then `init q` will work as the UNIX beards intended.
```shell
~ $ telinit
~ # telinit -h
Usage: telinit [OPTIONS] [q | Q | 0-9]
Options:
-h, --help This help text
-v, --version Show Finit version
-h, --help This help text
-V, --version Show Finit version
Commands:
q | Q Reload *.conf in /etc/finit.d/, like SIGHUP
0 - 9 Change runlevel: 0 halt, 6 reboot
```
0 Power-off the system, same as initctl poweroff
6 Reboot the system, same as initctl reboot
2, 3, 4, 5 Change runlevel. Starts services in new runlevel, stops any
services in prev. runlevel that are not allowed in new.
q, Q Reload *.conf in /etc/finit.d/, same as initctl reload or
sending SIGHUP to PID 1
1, s, S Enter system rescue mode, runlevel 1
Commands & Status
@@ -308,7 +280,6 @@ Finit also implements a more modern API to query status, and start/stop
services, called `initctl`. Unlike `telinit` the `initctl` tool does
not return until the given command has fully completed.
```shell
~ $ initctl -h
Usage: initctl [OPTIONS] <COMMAND>
@@ -332,21 +303,17 @@ not return until the given command has fully completed.
restart <JOB|NAME>[:ID] Restart (stop/start) service by job# or name
reload <JOB|NAME>[:ID] Reload (SIGHUP) service by job# or name
version Show Finit version
```
The `<!>` notation to a service stanza can be used empty, then it will
apply to `reload` and `runlevel` commands. I.e., when a service's
`.conf` file has been changed Finit will stop and start it instead. If
a service does *not* have `<!>` declared, the service will be reloaded
(`SIGHUP`:ed) in the `START` phase instead. The latter is the preferred
behaviour, but not all daemons support this, unfortunately.
For services *not* supporting `SIGHUP` the `<!>` notation in the .conf
file must be used to tell Finit to stop and start it on `reload` and
`runlevel` changes. If `<>` holds more [conditions](doc/conditions.md),
these will also affect how a service is maintained.
**Note:** even though it is possible to start services not belonging to
**Note:** even though it is possible to start services not belonging in
the current runlevel these services will not be respawned automatically
by Finit if they exit (crash). Hence, if the runlevel is 2, the below
Dropbear SSH service will not be restarted if it is killed or exits.
```shell
~ $ initctl status -v
1 running 476 [S12345] /sbin/watchdog -T 16 -t 2 -F /dev/watchdog
2 running 477 [S12345] /sbin/syslogd -n -b 3 -D
@@ -358,7 +325,33 @@ Dropbear SSH service will not be restarted if it is killed or exits.
5:2 inetd 0 [2345] /sbin/telnetd allow eth0:2323,eth2:2323,eth1:2323
6:1 inetd 0 [345] /sbin/dropbear allow eth0:222
6:2 inetd 0 [345] /sbin/dropbear allow *:22 deny eth0
```
Requirements
------------
Finit is capable of running on both desktop/server systems with udev and
embedded systems that usually come with BusyBox mdev. Finit probes for
them at runtime and expects `/dev/` to be writable, usually `devtmpfs`.
It is also possible to run on a statically set up `/dev` if needed. It
is however not a good idea to have both udev and mdev installed at the
same time, this will lead to unpredictable results.
At boot Finit calls either `mdev` or `udevd` to populate `/dev`, this is
done slightly differently and on systems with udev you might want to add
the following one-shot task early in your `/etc/finit.conf`:
run [S] /sbin/udevadm settle --timeout=120 -- Waiting for udev
Finit has a built-in Getty for TTYs, but requires a working `/bin/login`
or `/bin/sh`, if no TTYs are configured in `/etc/finit.conf`.
For a fully operational system `/var`, `/run` and `/tmp` must be set up
properly in `/etc/fstab` -- which is iterated over at boot.
The built-in Inetd requires `/etc/services` and `/etc/protocols` to work
with port names rather than numbers.
Running
-------
@@ -373,25 +366,29 @@ LILO, U-Boot/Barebox or RedBoot) configuration to append the following
to the kernel command line:
```shell
init=/sbin/finit
append="init=/sbin/finit"
```
Remember to also set up an initial `/etc/finit.conf` before rebooting!
![Finit starting Debian 6.0](images/finit-screenshot.jpg "Finit screenshot")
![Finit starting TroglOS](images/finit3-screenshot.png "Finit screenshot")
Debugging
---------
Add `finit_debug`, or `--debug`, to the kernel command line to enable
debug messages. See the output from `configure --help` for more on
how to assist debugging.
debug messages.
```shell
init=/sbin/finit --debug
append="init=/sbin/finit --debug"
```
To debug startup issues, in particular issues with getty/login, try
`configure --enable-fallback-shell`. When no TTYs are detected, and
Finit is configured with this option, Finit will try to start a bare
`/bin/sh` on the boot console.
Origin & References
-------------------
@@ -410,6 +407,7 @@ and proposed extensions.
[3]: http://smarden.org/runit/
[4]: http://en.wikipedia.org/wiki/Init
[5]: http://en.wikipedia.org/wiki/Runlevel
[6]: https://www.freedesktop.org/wiki/Software/systemd/
[9]: https://github.com/troglobit/troglos
[run-parts(8)]: http://manpages.debian.org/cgi-bin/man.cgi?query=run-parts
[original finit]: http://helllabs.org/finit/
+10 -45
View File
@@ -20,8 +20,6 @@ General
* Add halt/poweroff/shutdown symlinks to finit and convert reboot, but
only install symlinks if these tools don't already exist.
* Step state machine at shutdown instead of killing, same as shifting to
runlevel 0 or 6, then call external (newly installed?) tool to reboot.
* Add support for timed shutdown in Finit, including cancelled shutdown.
* SysV init and systemd use SIGUSR1 to restart their FIFO/D-Bus. Add
API restart to SIGHUP callback for the same functionality in Finit.
@@ -40,6 +38,8 @@ General
`service <SVC> stop|start|restart|reload|status` on top
* Add support for JSON output, or similar, from `initctl show`, e.g.
`initctl show --json`
* Improve output of `initctl show SVC`, list service uptime, last
ten relevant logs, etc. Similar to `systemctl show SVC`
* Add PRE and POST hooks for when switching between runlevels
@@ -55,11 +55,14 @@ to achieve compatibility would be to add a plugin to finit which reads
Inetd
-----
Add support for throttling connections.
Optimize interface filtering by using socket filter. The functions
`inet_*_peek()` and `inetd_is_allowed()` used for interace filtering
should be possible to rewrite as socket filters.
* Add support for throttling connections.
* Optimize interface filtering by using socket filter. The functions
`inet_*_peek()` and `inetd_is_allowed()` used for interace filtering
should be possible to rewrite as socket filters.
* Optimize HTTP/HTTPS inetd connections by adding basic support for the
`inetd` variant `redir http/tcp@eth0 nowait [2345] 127.0.0.1:8080`,
which would reduce the overhead of spawn the web server on each HTTP
connection, yet still provide a means of filtering access per iface.
Crond
@@ -93,44 +96,6 @@ the shell -- that way setting up one-time jobs would not entail
re-reading `/etc/finit.conf`
Watchdog
--------
Support for monitoring the health of the system and its processes.
* Add support for a `/dev/watchdog` built-in to replace both the BusyBox
watchdogd and my own refreshed uClinux-dist adaptation,
[watchdogd](https://github.com/troglobit/watchdogd)
* Add a system supervisor (pmon) to optionally reboot the system when a
process stops responding, or when a respawn limit has been reached, as
well as when system load gets too high. For details on UNIX loadavg,
see http://stackoverflow.com/questions/11987495/linux-proc-loadavg
- Default to 0.7 as MAX recommended load before warning and 0.9 reboot
* API for processes to register with the watchdog, libwdt
- Deeper monitoring of a process' main loop by instrumenting
- If a process is not heard from within its subscribed period time
reboot system or restart process.
- Add client libwdt library, inspired by old Westermo API and the
[libwdt][] API published in the [Fritz!Box source dump][], take for
instance the `fritzbox7170-source-files-04.87-tar.gz` drop and see
the `GPL-release_kernel.tgz` in `drivers/char/avm_new/` for the
kernel driver, and the `LGPL-GPL-release_target_tools.tgz` in `wdt/`
for the userland API.
- When a client process (a standard app/daemon instrumented with
libwdt calls in its main loop) registers with the watchdog, we raise
the RT priority to 98 (just below the kernel watchdog in prio).
This to ensure that system monitoring goes before anything else in
the system.
- Use UNIX domain sockets for communication between daemon and clients
* Separate `/etc/watchdog.conf` configuration file, or a perhaps
support for a more generic `/etc/finit.d/PLUGIN.conf`?
* Support enable/disable watchdog features:
- Supervise processes,
- CPU loadavg,
- Watch for file descriptor leaks,
- etc.
Documentation
-------------
+31 -17
View File
@@ -217,9 +217,14 @@ static int do_handle_emit(char *buf, size_t len)
return result;
}
/*
* In contrast to the SysV compat handling in plugins/initctl.c, when
* `initctl runlevel 0` is issued we default to POWERDOWN the system
* instead of just halting.
*/
static void cb(uev_t *w, void *UNUSED(arg), int UNUSED(events))
{
int sd;
int sd, lvl;
struct init_request rq;
sd = accept(w->fd, NULL, NULL);
@@ -255,26 +260,19 @@ static void cb(uev_t *w, void *UNUSED(arg), int UNUSED(events))
switch (rq.cmd) {
case INIT_CMD_RUNLVL:
switch (rq.runlevel) {
case '0':
_d("Halting system (SIGUSR2)");
do_shutdown(SHUT_OFF);
break;
case 's':
case 'S':
_d("Cannot enter bootstrap after boot ...");
rq.runlevel = '1';
rq.runlevel = '1'; /* Single user mode */
/* Fall through to regular processing */
case '1'...'5':
case '7'...'9':
case '0'...'9':
_d("Setting new runlevel %c", rq.runlevel);
service_runlevel(rq.runlevel - '0');
break;
case '6':
_d("Rebooting system (SIGUSR1)");
do_shutdown(SHUT_REBOOT);
lvl = rq.runlevel - '0';
if (lvl == 0)
halt = SHUT_OFF;
if (lvl == 6)
halt = SHUT_REBOOT;
service_runlevel(lvl);
break;
default:
@@ -319,13 +317,25 @@ static void cb(uev_t *w, void *UNUSED(arg), int UNUSED(events))
case INIT_CMD_GET_RUNLEVEL:
rq.runlevel = runlevel;
result = 0;
break;
case INIT_CMD_ACK:
_d("Client failed reading ACK");
goto leave;
case INIT_CMD_WDOG_HELLO:
if (rq.runlevel <= 0) {
result = 1;
break;
}
if (wdogpid > 0 && wdogpid != rq.runlevel) {
kill(wdogpid, SIGTERM);
do_sleep(1);
}
wdogpid = rq.runlevel;
break;
default:
_d("Unsupported cmd: %d", rq.cmd);
break;
@@ -347,6 +357,7 @@ leave:
int api_init(uev_ctx_t *ctx)
{
int sd;
mode_t oldmask;
struct sockaddr_un sun = {
.sun_family = AF_UNIX,
.sun_path = INIT_SOCKET,
@@ -359,17 +370,20 @@ int api_init(uev_ctx_t *ctx)
}
erase(INIT_SOCKET);
oldmask = umask(0077);
if (-1 == bind(sd, (struct sockaddr*)&sun, sizeof(sun)))
goto error;
if (-1 == listen(sd, 10))
goto error;
umask(oldmask);
if (!uev_io_init(ctx, &api_watcher, cb, NULL, sd, UEV_READ))
return 0;
error:
_pe("Failed intializing API socket");
umask(oldmask);
close(sd);
return 1;
}
+4 -2
View File
@@ -30,6 +30,7 @@
#include <lite/lite.h>
#include "finit.h"
#include "util.h"
static int do_send(struct init_request *rq)
{
@@ -39,7 +40,7 @@ static int do_send(struct init_request *rq)
if (fd == -1) {
if (!fexist(FINIT_FIFO)) {
fprintf(stderr, "%s does not support %s!\n", __progname, FINIT_FIFO);
fprintf(stderr, "%s does not support %s!\n", prognm, FINIT_FIFO);
return 1;
}
@@ -108,7 +109,7 @@ static int usage(int rc)
" q, Q Reload *.conf in /etc/finit.d/, same as initctl reload or\n"
" sending SIGHUP to PID 1\n"
" 1, s, S Enter system rescue mode, runlevel 1\n"
"\n", __progname);
"\n", prognm);
return rc;
}
@@ -123,6 +124,7 @@ int client(int argc, char *argv[])
};
silent = 1;
progname(argv[0]);
while ((c = getopt_long(argc, argv, "h?v", long_options, NULL)) != EOF) {
switch(c) {
case 'v':
+1 -4
View File
@@ -89,14 +89,11 @@ static void cond_update(const char *name)
svc_t *svc;
_d("%s", name);
if (!name)
return;
for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) {
if (!svc_has_cond(svc) || !cond_affects(name, svc->cond))
continue;
_d("%s: match <%s> %s", name, svc->cond, svc->cmd);
_d("%s: match <%s> %s", name ?: "nil", svc->cond, svc->cmd);
service_step(svc);
}
}
+3 -6
View File
@@ -197,7 +197,7 @@ void conf_parse_rlimit(char *line)
} else {
const char *err = NULL;
new = strtonum(tok, 0, 2 << 31, &err);
new = strtonum(tok, 0, (long long)2 << 31, &err);
if (err)
goto fail;
}
@@ -340,16 +340,13 @@ static void parse_dynamic(char *line, time_t mtime)
if (MATCH_CMD(line, "#", x))
return;
/* Monitored daemon, will be respawned on exit, as
* long as the (optional) service callback returns
* non-zero */
/* Monitored daemon, will be respawned on exit */
if (MATCH_CMD(line, "service ", x)) {
service_register(SVC_TYPE_SERVICE, x, mtime, NULL);
return;
}
/* One-shot task, will not be respawned. Only runs if
* the (optional) service callback returns true */
/* One-shot task, will not be respawned */
if (MATCH_CMD(line, "task ", x)) {
service_register(SVC_TYPE_TASK, x, mtime, NULL);
return;
+21 -16
View File
@@ -1,4 +1,4 @@
AC_INIT(Finit, 3.0-rc1, https://github.com/troglobit/finit/issues, finit, http://troglobit.com/finit.html)
AC_INIT(Finit, 3.0-rc2, https://github.com/troglobit/finit/issues, finit, http://troglobit.com/finit.html)
AM_INIT_AUTOMAKE([1.11 foreign no-dist-gzip dist-xz subdir-objects])
AM_SILENT_RULES([yes])
@@ -33,7 +33,7 @@ AC_TYPE_UINT16_T
AC_TYPE_UINT32_T
# Check for required libraries
PKG_CHECK_MODULES([uev], [libuev >= 1.4.2])
PKG_CHECK_MODULES([uev], [libuev >= 1.5.2])
PKG_CHECK_MODULES([lite], [libite >= 1.8.2])
# Check for configured Finit features
@@ -41,12 +41,18 @@ AC_ARG_ENABLE(emergency_shell,
AS_HELP_STRING([--enable-emergency-shell], [Experimental emergency fallback at boot.
Only use this for debugging very early boot problems with Finit.]))
AC_ARG_ENABLE(fallback_shell,
AS_HELP_STRING([--enable-fallback-shell], [Start a shell if no TTYs can start.]))
AC_ARG_ENABLE(rw-rootfs,
AS_HELP_STRING([--enable-rw-rootfs], [Remount / R/W at boot, usually not for embedded]))
AC_ARG_ENABLE(silent,
AS_HELP_STRING([--enable-silent], [Completely silent operation, not even boot messages]))
AC_ARG_ENABLE(watchdog,
AS_HELP_STRING([--enable-watchdog], [Enable built-in watchdog, uses /dev/watchdog]))
AC_ARG_ENABLE(inetd,
AS_HELP_STRING([--disable-inetd], [Disable built-in inetd super server, default enabled]))
@@ -97,10 +103,6 @@ AC_ARG_WITH(console,
AS_HELP_STRING([--with-console=DEV], [Console to use, default: /dev/console]),
[console=$withval], [console=/dev/console])
AC_ARG_WITH(shell,
AS_HELP_STRING([--with-shell=PATH], [Fallback shell to use, default: /bin/sh]),
[shell=$withval], [shell=/bin/sh])
AC_ARG_WITH(username,
AS_HELP_STRING([--with-username=USER], [User for 'startx' .conf option, default: root]),
[username=$withval], [username=root])
@@ -124,6 +126,9 @@ AC_ARG_WITH(random-seed,
AS_IF([test "x$enable_emergency_shell" = "xyes"], [
AC_DEFINE(EMERGENCY_SHELL, 1, [Fork off init and let PID 1 wait and start /bin/sh if init crashes.])])
AS_IF([test "x$enable_fallback_shell" = "xyes"], [
AC_DEFINE(FALLBACK_SHELL, 1, [Start /bin/sh on console if no TTYs.])])
AS_IF([test "x$enable_rw_rootfs" = "xyes"], [
AC_DEFINE(REMOUNT_ROOTFS, 1, [Remount / as rw at boot])])
@@ -132,14 +137,18 @@ AS_IF([test "x$enable_silent" = "xyes"], [
], [
AC_DEFINE(SILENT_MODE, 0, [Normal output, default])])
AS_IF([test "x$enable_watchdog" = "xyes"], [
AC_DEFINE(BUILTIN_WATCHDOG, 1, [Enable built-in watchdog, kicks on /dev/watchdog])])
### Disable features ###########################################################################
AS_IF([test "x$enable_inetd" != "xno"], enable_inetd="yes", [
AS_IF([test "x$enable_inetd" != "xno"],
enable_inetd="yes", [
AC_DEFINE(INETD_DISABLED, 1, [Disable built-in inetd])])
AS_IF([test "x$enable_quiet" != "xno"], [
AC_DEFINE(QUIET_MODE, 0, [Will print stopping/starting/etc messages at runtime])
AC_DEFINE(QUIET_MODE, 1, [Silent, after initial boot, no stopping/starting messages. Default: 1])
], [
AC_DEFINE(QUIET_MODE, 1, [Silent at runtime, after initial boot, default])])
AC_DEFINE(QUIET_MODE, 0, [Silent, after initial boot, no stopping/starting messages. Default: 1])])
### With features ##############################################################################
AS_IF([test "x$with_fifo" != "xno"], [
@@ -176,11 +185,6 @@ AS_IF([test "x$with_console" != "xno"], [
console=/dev/console])])
AC_DEFINE_UNQUOTED(CONSOLE, "$console", [Default console to use])
AS_IF([test "x$with_shell" != "xno"], [
AS_IF([test "x$shell" = "xyes"], [
shell=/bin/sh])])
AC_DEFINE_UNQUOTED(FALLBACK_SHELL, "$shell", [Used if no login getty])
AS_IF([test "x$with_username" != "xno"], [
AS_IF([test "x$username" = "xyes"], [
username=root])])
@@ -203,8 +207,9 @@ AS_IF([test "x$with_random_seed" != "xno"], [
AC_DEFINE_UNQUOTED(RANDOMSEED, "$lurvig", [Improve random at boot by seeding it with sth from before.])])
# Control build with automake flags
AM_CONDITIONAL(STATIC, [test "x$enable_static" = "xyes"])
AM_CONDITIONAL(INETD, [test "x$enable_inetd" = "xyes"])
AM_CONDITIONAL(STATIC, [test "x$enable_static" = "xyes"])
AM_CONDITIONAL(INETD, [test "x$enable_inetd" = "xyes"])
AM_CONDITIONAL(WATCHDOGD, [test "x$enable_watchdog" = "xyes"])
# Generate all files
AC_OUTPUT
+3
View File
@@ -166,6 +166,9 @@ The `run`, `task`, `service`, or `inetd` stanzas also allow the keyword
`log` to redirect `stderr` and `stdout` of the application to syslog,
using `logger`.
Worth noting is that conditions is allowed for all these stanzas. For a
detailed description, see the [Conditions](conditions.md) document.
/etc/finit.d
------------
+41
View File
@@ -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:
-->
+2 -4
View File
@@ -100,13 +100,11 @@ int run(char *cmd)
pid = fork();
if (0 == pid) {
int i;
FILE *fp;
struct sigaction sa;
/* Reset signal handlers that were set by the parent process */
for (i = 1; i < NSIG; i++)
DFLSIG(sa, i, 0);
sig_unblock();
setsid();
/* Always redirect stdio for run() */
fp = fopen("/dev/null", "w");
+20 -31
View File
@@ -25,7 +25,6 @@
#include "config.h" /* Generated by configure script */
#include <ctype.h>
#include <glob.h>
#include <dirent.h>
#ifdef HAVE_FSTAB_H
#include <fstab.h>
@@ -46,10 +45,12 @@
#include "sm.h"
#include "tty.h"
#include "utmp-api.h"
#include "watchdog.h"
int debug = 0;
int quiet = QUIET_MODE; /* Delayed disable of silent mode. */
int silent = SILENT_MODE; /* Completely silent, including boot */
int wdogpid = 0; /* No watchdog by default */
int runlevel = 0; /* Bootstrap 'S' */
int cfglevel = RUNLEVEL; /* Fallback if no configured runlevel */
int prevlevel = -1;
@@ -119,26 +120,7 @@ static int fsck(int pass)
static void networking(void)
{
size_t i;
glob_t gl;
FILE *fp;
char buf[160];
/* Setup kernel specific settings, e.g. allow broadcast ping, etc. */
glob("/run/sysctl.d/*.conf", 0, NULL, &gl);
glob("/etc/sysctl.d/*.conf", GLOB_APPEND, NULL, &gl);
glob("/usr/local/lib/sysctl.d/*.conf", GLOB_APPEND, NULL, &gl);
glob("/usr/lib/sysctl.d/*.conf", GLOB_APPEND, NULL, &gl);
glob("/lib/sysctl.d/*.conf", GLOB_APPEND, NULL, &gl);
glob("/mnt/sysctl.d/*.conf", GLOB_APPEND, NULL, &gl);
glob("/etc/sysctl.conf", GLOB_APPEND, NULL, &gl);
if (gl.gl_pathc > 0) {
for (i = 0; i < gl.gl_pathc; i++) {
snprintf(buf, sizeof(buf), "/sbin/sysctl -e -p %s >/dev/null", gl.gl_pathv[i]);
run(buf);
}
globfree(&gl);
}
/* Run user network start script if enabled */
if (network) {
@@ -149,7 +131,8 @@ static void networking(void)
/* Debian/Ubuntu/Busybox interfaces file */
fp = fopen("/etc/network/interfaces", "r");
if (fp) {
i = 0;
int i = 0;
char buf[160];
/* Bring up all 'auto' interfaces */
while (fgets(buf, sizeof(buf), fp)) {
@@ -232,7 +215,6 @@ static void emergency_shell(void)
int main(int argc, char* argv[])
{
int err;
char *devfsd;
uev_ctx_t loop;
@@ -325,7 +307,13 @@ int main(int argc, char* argv[])
else
devfsd = "/lib/systemd/systemd-udevd --daemon";
}
run_interactive(devfsd, "Populating device tree");
if (fexist("/sbin/udevadm")) {
run("/sbin/udevadm trigger --action=add --type=subsystems");
run("/sbin/udevadm trigger --action=add --type=devices");
run("/sbin/udevadm settle --timeout=120");
}
/*
* Load plugins first, finit.conf may contain references to
@@ -338,6 +326,11 @@ int main(int argc, char* argv[])
*/
conf_parse_config();
/*
* Start built-in watchdog as soon as possible, if enabled
*/
watchdog(argv[0]);
/* Set hostname as soon as possible, for syslog et al. */
set_hostname(&hostname);
@@ -362,19 +355,12 @@ int main(int argc, char* argv[])
plugin_run_hooks(HOOK_ROOTFS_UP);
umask(0);
print_desc("Mounting filesystems", NULL);
err = run("/bin/mount -na");
print_result(err);
if (err)
if (run_interactive("/bin/mount -na", "Mounting filesystems"))
plugin_run_hooks(HOOK_MOUNT_ERROR);
run("/sbin/swapon -ea");
umask(0022);
/* Cleanup of stale files, if any still linger on. */
run_interactive("rm -rf /tmp/* /var/run/* /var/lock/*", "Cleaning up temporary directories");
/* Base FS up, enable standard SysV init signals */
sig_setup(&loop);
@@ -410,11 +396,14 @@ int main(int argc, char* argv[])
if (runparts && fisdir(runparts)) {
_d("Running startup scripts in %s ...", runparts);
run_parts(runparts, NULL);
service_reload_dynamic();
}
/* Convenient SysV compat for when you just don't care ... */
if (!access(FINIT_RC_LOCAL, X_OK))
if (!access(FINIT_RC_LOCAL, X_OK)) {
run_interactive(FINIT_RC_LOCAL, "Calling %s", FINIT_RC_LOCAL);
service_reload_dynamic();
}
/* Hooks that should run at the very end */
plugin_run_hooks(HOOK_SYSTEM_UP);
+3 -3
View File
@@ -63,10 +63,11 @@
#define INIT_CMD_START_SVC 10
#define INIT_CMD_STOP_SVC 11
#define INIT_CMD_RELOAD_SVC 12 /* SIGHUP service */
#define INIT_CMD_RESTART_SVC 13 /* STOP + START service */
#define INIT_CMD_RESTART_SVC 13 /* STOP + START service */
#define INIT_CMD_QUERY_INETD 14
#define INIT_CMD_EMIT 15
#define INIT_CMD_GET_RUNLEVEL 16
#define INIT_CMD_WDOG_HELLO 128 /* Watchdog register and hello */
#define INIT_CMD_NACK 254
#define INIT_CMD_ACK 255
@@ -81,6 +82,7 @@ struct init_request {
extern int debug;
extern int quiet;
extern int silent;
extern int wdogpid;
extern int runlevel;
extern int cfglevel;
extern int prevlevel;
@@ -93,8 +95,6 @@ extern char *runparts;
extern char *console;
extern uev_ctx_t *ctx;
extern char *__progname;
#endif /* FINIT_H_ */
/**
+26 -4
View File
@@ -28,6 +28,7 @@
#include <stdio.h>
#include <sys/ioctl.h>
#include <sys/utsname.h>
#include <sys/ttydefaults.h> /* Not included by default in musl libc */
#include <termios.h>
#include "finit.h"
@@ -73,13 +74,34 @@ static void stty(int fd, speed_t speed)
cfsetispeed(&term, speed);
cfsetospeed(&term, speed);
tcsetattr(fd, TCSAFLUSH, &term);
tcflush(fd, TCIOFLUSH);
/* Clear screen -- disabled until we decide on config to disable/enable */
//print("\033[r\033[H\033[J");
}
/* Disable modem specific flags */
term.c_cflag &= (0|CSTOPB|PARENB|PARODD);
term.c_cflag &= ~CRTSCTS;
term.c_cflag |= CLOCAL;
/* Timeouts, minimum chars and default flags */
term.c_cc[VTIME] = 0;
term.c_cc[VMIN] = 1;
term.c_iflag = ICRNL|IXON|IXOFF;
term.c_oflag = OPOST|ONLCR;
term.c_cflag |= CS8|CREAD|HUPCL|CBAUDEX;
term.c_lflag |= ISIG|ICANON|ECHO|ECHOE|ECHOK|ECHOKE;
/* Reset special characters to defaults */
term.c_cc[VINTR] = CTRL('C');
term.c_cc[VQUIT] = CTRL('\\');
term.c_cc[VEOF] = CTRL('D');
term.c_cc[VEOL] = '\n';
term.c_cc[VKILL] = CTRL('U');
term.c_cc[VERASE] = CERASE;
tcsetattr(fd, TCSANOW, &term);
/* Clear screen in silent mode */
if (silent)
print("\033[r\033[H\033[J");
}
/*
* Parse and display a line from /etc/issue
+6 -6
View File
@@ -181,11 +181,8 @@ int print_result(int fail)
}
/*
* Log to stderr until syslogd has started, then openlog() and continue
* logging as a regular daemon.
*
* TODO: Log to /dev/kmsg instead of stderr until syslogd has started
* Need to convert facility+prio => "<VAL> msg"
* Log to /dev/kmsg until syslogd has started, then openlog()
* and continue logging as a regular daemon.
*/
void logit(int prio, const char *fmt, ...)
{
@@ -197,12 +194,15 @@ void logit(int prio, const char *fmt, ...)
fp = fopen("/dev/kmsg", "w");
if (fp) {
if (debug)
prio = LOG_ERR;
fprintf(fp, "<%d>finit[1]:", LOG_DAEMON | prio);
vfprintf(fp, fmt, ap);
fclose(fp);
} else {
fprintf(stderr, "Failed opening /dev/kmsg for appending ...\n");
if (prio <= LOG_ERR)
if (debug || prio <= LOG_ERR)
vfprintf(stderr, fmt, ap);
}
va_end(ap);
+7
View File
@@ -0,0 +1,7 @@
_______ __ _____ ___ __ ___________ _______
/" "||" \ (\" \|" \ |" \(" _ ")/" __ )
(: ______)|| | |.\\ \ | || |)__/ \\__/(__/ _) ./
\/ | |: | |: \. \\ | |: | \\_ / / //
// ___) |. | |. \ \. | |. | |. | __ \_ \\
(: ( /\ |\| \ \ | /\ |\ \: | (: \__) :\
\__/ (__\_|_)\___|\____\)(__\_|_) \__| \_______)
Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

+53 -16
View File
@@ -321,9 +321,8 @@ void inetd_stop(inetd_t *inetd)
}
}
static struct servent *getent_service(char *service, char *proto)
static struct servent *fallback_service(char *service, char *proto)
{
#ifdef ENABLE_STATIC
int service_num;
static struct servent lfs;
@@ -339,29 +338,50 @@ static struct servent *getent_service(char *service, char *proto)
}
return NULL;
}
static struct servent *getent_service(char *service, char *proto)
{
struct servent *ent;
#ifdef ENABLE_STATIC
ent = fallback_service(service, proto);
#else
return getservbyname(service, proto);
ent = getservbyname(service, proto);
if (!ent)
ent = fallback_service(service, proto);
#endif
return ent;
}
static struct protoent *fallback_proto(char *proto)
{
int proto_num;
static struct protoent lfp;
proto_num = fgetint("/etc/protocols", " \n\t", proto);
if (proto_num > 0) {
lfp.p_name = proto;
lfp.p_proto = proto_num;
return &lfp;
}
return NULL;
}
static struct protoent *getent_proto(char *proto)
{
struct protoent *ent;
#ifdef ENABLE_STATIC
int proto_num;
static struct protoent lfp;
proto_num = fgetint("/etc/protocols", " \n\t", proto);
if (proto_num > 0) {
lfp.p_name = proto;
lfp.p_proto = proto_num;
return &lfp;
}
return NULL;
ent = fallback_proto(proto);
#else
return getprotobyname(proto);
ent = getprotobyname(proto);
if (!ent)
ent = fallback_proto(proto);
#endif
return ent;
}
static int getent(char *service, char *proto, struct servent **sv, struct protoent **pv)
@@ -615,6 +635,23 @@ int inetd_filter_str(inetd_t *inetd, char *str, size_t len)
return 0;
}
svc_t *inetd_find_svc(char *path, char *service, char *proto)
{
svc_t *svc;
for (svc = svc_inetd_iterator(1); svc; svc = svc_inetd_iterator(0)) {
if (strncmp(path, svc->cmd, strlen(svc->cmd)))
continue;
if (inetd_match(&svc->inetd, service, proto)) {
_d("Found a matching inetd svc for %s %s %s", path, service, proto);
return svc;
}
}
return NULL;
}
/*
* This function is called to add a new, unique, inetd service. When an
* ifname is given as argument this means *only* run service on this
+13 -12
View File
@@ -54,22 +54,23 @@ typedef struct {
TAILQ_HEAD(, inetd_filter) filters;
} inetd_t;
int inetd_check_loop (struct sockaddr *sa, socklen_t len, char *name);
int inetd_check_loop(struct sockaddr *sa, socklen_t len, char *name);
int inetd_start (inetd_t *inetd);
void inetd_stop (inetd_t *inetd);
int inetd_start (inetd_t *inetd);
void inetd_stop (inetd_t *inetd);
int inetd_new (inetd_t *inetd, char *name, char *service, char *proto,
int forking, svc_t *svc);
int inetd_del (inetd_t *inetd);
int inetd_new (inetd_t *inetd, char *name, char *service, char *proto, int forking, svc_t *svc);
int inetd_del (inetd_t *inetd);
int inetd_match (inetd_t *inetd, char *service, char *proto);
int inetd_filter_str (inetd_t *inetd, char *str, size_t len);
svc_t *inetd_find_svc (char *path, char *service, char *proto);
int inetd_flush (inetd_t *inetd);
int inetd_allow (inetd_t *inetd, char *ifname);
int inetd_deny (inetd_t *inetd, char *ifname);
int inetd_is_allowed (inetd_t *inetd, char *ifname);
int inetd_match (inetd_t *inetd, char *service, char *proto);
int inetd_filter_str(inetd_t *inetd, char *str, size_t len);
int inetd_flush (inetd_t *inetd);
int inetd_allow (inetd_t *inetd, char *ifname);
int inetd_deny (inetd_t *inetd, char *ifname);
int inetd_is_allowed(inetd_t *inetd, char *ifname);
#endif /* FINIT_INETD_H_ */
+3 -1
View File
@@ -38,6 +38,7 @@
#include "cond.h"
#include "helpers.h"
#include "service.h"
#include "util.h"
#include "utmp-api.h"
#define _PATH_COND _PATH_VARRUN "finit/cond/"
@@ -439,7 +440,7 @@ static int usage(int rc)
" halt Halt system\n"
" poweroff Halt and power off system\n"
" utmp show Raw dump of UTMP/WTMP db\n"
" version Show Finit version\n\n", __progname);
" version Show Finit version\n\n", prognm);
return rc;
}
@@ -471,6 +472,7 @@ int main(int argc, char *argv[])
{NULL, 0, NULL, 0}
};
progname(argv[0]);
while ((c = getopt_long(argc, argv, "dh?v", long_options, NULL)) != EOF) {
switch(c) {
case 'h':
+3 -2
View File
@@ -1,11 +1,12 @@
AM_LDFLAGS = -module -avoid-version -shared
AM_CFLAGS = -W -Wall -Wextra -std=gnu99
AM_CPPFLAGS = -U_FORTIFY_SOURCE
AM_CPPFLAGS += -D_XOPEN_SOURCE=600 -D_BSD_SOURCE -D_GNU_SOURCE -D_DEFAULT_SOURCE
AM_CPPFLAGS += $(lite_CFLAGS)
if STATIC
noinst_LTLIBRARIES = libplug.la
libplug_la_SOURCES = bootmisc.c hwclock.c initctl.c pidfile.c tty.c urandom.c
libplug_la_SOURCES = bootmisc.c hwclock.c initctl.c pidfile.c procps.c tty.c urandom.c
if BUILD_ALSA_UTILS_PLUGIN
libplug_la_SOURCES += alsa-utils.c
@@ -50,7 +51,7 @@ libplug_la_SOURCES += resolvconf.c
endif
else
pkglib_LTLIBRARIES = bootmisc.la hwclock.la initctl.la pidfile.la tty.la urandom.la
pkglib_LTLIBRARIES = bootmisc.la hwclock.la initctl.la pidfile.la procps.la tty.la urandom.la
if BUILD_ALSA_UTILS_PLUGIN
pkglib_LTLIBRARIES += alsa-utils.la
+69 -1
View File
@@ -21,6 +21,8 @@
* THE SOFTWARE.
*/
#include <ftw.h>
#include <mntent.h>
#include <string.h>
#include <lite/lite.h>
@@ -30,12 +32,73 @@
#include "../plugin.h"
#include "../utmp-api.h"
static int is_tmpfs(char *path)
{
int tmpfs = 0;
FILE *fp;
char *dir;
struct mntent *mnt;
/* If path is a symlink, check what it resolves to */
dir = realpath(path, NULL);
if (!dir)
return 0; /* Outlook not so good */
fp = setmntent("/proc/mounts", "r");
if (!fp) {
free(dir);
return 0; /* Dunno, maybe not */
}
while ((mnt = getmntent(fp))) {
if (!strcmp(dir, mnt->mnt_dir))
break;
}
if (mnt && !strcmp("tmpfs", mnt->mnt_type))
tmpfs = 1;
endmntent(fp);
free(dir);
return tmpfs;
}
static void create(char *path, mode_t mode, uid_t uid, gid_t gid)
{
if (touch(path) || chmod(path, mode) || chown(path, uid, gid))
_w("Failed creating %s properl.", path);
}
static int do_clean(const char *fpath, const struct stat *UNUSED(sb), int UNUSED(tflag), struct FTW *ftwbuf)
{
if (ftwbuf->level == 0)
return 1;
_d("Removing %s ...", fpath);
(void)remove(fpath);
return 0;
}
/* We can safely skip tmpfs, nothing to clean from previous boot there */
static void bootclean(void)
{
char *dir[] = {
"/tmp/",
"/var/run/",
"/var/lock/",
NULL
};
for (int i = 0; dir[i]; i++) {
if (is_tmpfs(dir[i]))
continue;
nftw(dir[i], do_clean, 20, FTW_DEPTH);
}
}
/*
* Setup standard FHS 2.3 structure in /var, and write runlevel to UTMP
*/
@@ -43,7 +106,11 @@ static void setup(void *UNUSED(arg))
{
int gid;
/* Cleanup stale files, if any still linger on. */
bootclean();
_d("Setting up FHS structure in /var ...");
umask(0);
makedir("/var/cache", 0755);
makedir("/var/games", 0755);
makedir("/var/lib", 0755);
@@ -60,7 +127,6 @@ static void setup(void *UNUSED(arg))
makedir("/var/lock", 1777);
makedir("/var/run", 0755);
}
makedir("/var/lock/subsys",0755); /* Needed by D-Bus plugin */
makedir("/var/log", 0755);
makedir("/var/mail", 0755);
makedir("/var/opt", 0755);
@@ -104,6 +170,8 @@ static void setup(void *UNUSED(arg))
makedir("/var/run/sshd", 01755); /* OpenSSH */
makefifo("/dev/xconsole", 0640); /* sysklogd */
chown("/dev/xconsole", 0, getgroup("tty"));
umask(022);
}
static plugin_t plugin = {
+14 -8
View File
@@ -30,25 +30,32 @@
#define NAME "chargen"
#define PATTERN "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ "
static char *generator(char *buf, size_t len)
static char *generator(char *buf, size_t buflen)
{
size_t num;
size_t num, len, width = 72;
static size_t pos = 0;
const char pattern[] = PATTERN;
len = 72;
if (buflen < width)
width = buflen;
len = width;
if (len + 3 > buflen)
len = buflen - 3;
if (pos + len > sizeof(pattern)) {
num = sizeof(pattern) - pos;
len -= num;
} else {
num = 72;
num = width;
if (num + 3 > buflen)
num = buflen - 3;
len = 0;
}
strncpy(&buf[0], &pattern[pos], num--);
strncpy(buf, &pattern[pos], num--);
if (len++)
strncpy(&buf[num], pattern, len);
strcat(buf, "\r\n");
strlcat(buf, "\r\n", width);
if (++pos >= sizeof(pattern) - 1)
pos = 0;
@@ -75,10 +82,9 @@ static int send_peer(int sd, char *buf, ssize_t len, struct sockaddr *sa, sockle
return sendto(sd, pattern, strlen(pattern), MSG_DONTWAIT, sa, sa_len);
}
static int cb(int type)
static int cb(int UNUSED(type))
{
int sd = STDIN_FILENO;
ssize_t len;
char buf[BUFSIZ];
struct sockaddr_storage sa;
socklen_t sa_len = sizeof(sa);
+1 -1
View File
@@ -64,7 +64,7 @@ static int send_peer(int sd, char *buf, ssize_t len, struct sockaddr *sa, sockle
return sendto(sd, now, strlen(now), MSG_DONTWAIT, sa, sa_len);
}
static int cb(int type)
static int cb(int UNUSED(type))
{
int sd = STDIN_FILENO;
char buf[BUFSIZ];
+5
View File
@@ -31,12 +31,17 @@
static void setup(void *UNUSED(arg))
{
umask(0);
_d("Starting D-Bus ...");
makedir("/var/run/dbus", 0755);
makedir("/var/lock/subsys", 0755);
makedir("/var/lock/subsys/messagebus", 0755);
run("dbus-uuidgen --ensure");
erase("/var/run/dbus/pid");
run_interactive("dbus-daemon --system", "Starting D-Bus");
umask(022);
}
static plugin_t plugin = {
+1 -1
View File
@@ -27,7 +27,7 @@
#include "../plugin.h"
static int cb(int type)
static int cb(int UNUSED(type))
{
int sd = STDIN_FILENO;
char buf[BUFSIZ];
+10 -21
View File
@@ -39,13 +39,6 @@
#include "../sig.h"
#include "../service.h"
/*
* Old-style SysV shutdown sends a setenv cmd INIT_HALT with "=HALT",
* "=POWERDOWN", or "" to cancel shutdown, before requesting change to
* runlevel 6 over the /dev/initctl FIFO.
*/
shutop_t halt = SHUT_DEFAULT;
static void parse(void *arg, int fd, int events);
static void setup(void *arg);
@@ -99,11 +92,15 @@ static void set_env(char *data)
}
/*
* Standard reboot/shutdown utilities talk to init using /dev/initctl.
* Standard reboot/shutdown utilities talk to init using /run/initctl.
* We should check if the fifo was recreated and reopen it.
*
* For SysV compatibility the default is to halt the system when issuing
* `init 0`, unless INIT_HALT=POWERDOWN, as performed by the SysV utils.
*/
static void parse(void *UNUSED(arg), int fd, int UNUSED(events))
{
int lvl;
struct init_request rq;
while (1) {
@@ -132,25 +129,17 @@ static void parse(void *UNUSED(arg), int fd, int UNUSED(events))
switch (rq.cmd) {
case INIT_CMD_RUNLVL:
switch (rq.runlevel) {
case '0':
_d("Halting system (SIGUSR1 or SIGUSR2)");
do_shutdown(halt);
break;
case 's':
case 'S':
rq.runlevel = '1';
/* Fall through to regular processing */
case '1'...'5':
case '7'...'9':
case '0'...'9':
_d("Setting new runlevel %c", rq.runlevel);
service_runlevel(rq.runlevel - '0');
break;
case '6':
_d("Rebooting system (SIGTERM)");
do_shutdown(SHUT_REBOOT);
lvl = rq.runlevel - '0';
if (lvl == 6)
halt = SHUT_REBOOT;
service_runlevel(lvl);
break;
default:
+74
View File
@@ -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
View File
@@ -27,43 +27,22 @@
#include "../helpers.h"
#include "../plugin.h"
/*
* No need to clean up files in /etc/resolvconf/run/interface/
* this is already taken care of by bootclean
*/
static void setup(void *UNUSED(arg))
{
#ifdef USE_ETC_RESOLVCONF_RUN
DIR *dir;
struct dirent *d;
#endif
_d("Setting up the resolver ...");
#ifdef USE_ETC_RESOLVCONF_RUN
makepath("/dev/shm/network");
makepath("/dev/shm/resolvconf/interface");
mkpath("/etc/resolvconf", 0755);
mkpath("/etc/resolvconf/run", 0755);
mkpath("/var/run/resolvconf", 0755);
mkpath("/var/run/resolvconf/interface", 0755);
if ((dir = opendir("/etc/resolvconf/run/interface")) != NULL) {
while ((d = readdir(dir)) != NULL) {
if (isalnum(d->d_name[0]))
continue;
snprintf(line, sizeof(line),
"/etc/resolvconf/run/interface/%s", d->d_name);
unlink(line);
}
closedir(dir);
}
#endif
#ifdef USE_VAR_RUN_RESOLVCONF
makepath("/var/run/resolvconf/interface");
symlink("../../../etc/resolv.conf", "/var/run/resolvconf/resolv.conf");
#endif
#ifdef USE_ETC_RESOLVCONF_RUN
touch("/etc/resolvconf/run/enable-updates");
chdir("/etc/resolvconf/run/interface");
run_parts("/etc/resolvconf/update.d", "-i");
chdir("/");
#endif /* USE_ETC_RESOLVCONF_RUN */
}
static plugin_t plugin = {
+2 -2
View File
@@ -71,14 +71,14 @@ static int send_peer(int sd, char *buf, ssize_t len, struct sockaddr *sa, sockle
{
char *now;
now = rfctime(buf, &len);
now = rfctime(buf, (size_t *)&len);
if (!now)
return -1; /* On error, close connection. */
return sendto(sd, now, len, MSG_DONTWAIT, sa, sa_len);
}
static int cb(int type)
static int cb(int UNUSED(type))
{
int sd = STDIN_FILENO;
char buf[BUFSIZ];
+4
View File
@@ -37,6 +37,8 @@ static void setup(void *UNUSED(arg))
#endif
char line[LINE_SIZE];
umask(0);
makedir("/var/run/console", 01777);
snprintf(line, sizeof(line), "/var/run/console/%s", username);
touch(line);
@@ -54,6 +56,8 @@ static void setup(void *UNUSED(arg))
if (fexist("/sbin/restorecon"))
run("/sbin/restorecon /tmp/.ICE-unix /tmp/.X11-unix");
umask(022);
}
static plugin_t plugin = {
+8 -5
View File
@@ -28,6 +28,7 @@
#include <string.h>
#include <unistd.h>
#include <sys/reboot.h>
#include "util.h"
#ifndef RB_SW_SUSPEND /* Since Linux 2.5.18, but not in GLIBC until 2.19 */
#define RB_SW_SUSPEND 0xd000fce2
@@ -43,16 +44,15 @@ typedef enum {
static cmd_t cmd = CMD_UNKNOWN;
static char *msg = NULL;
extern char *__progname;
static void translate(void)
{
if (cmd == CMD_UNKNOWN) {
if (!strcmp(__progname, "halt") || !strcmp(__progname, "shutdown"))
if (!strcmp(prognm, "halt") || !strcmp(prognm, "shutdown"))
cmd = CMD_HALT;
else if (!strcmp(__progname, "poweroff"))
else if (!strcmp(prognm, "poweroff"))
cmd = CMD_POWEROFF;
else if (!strcmp(__progname, "suspend"))
else if (!strcmp(prognm, "suspend"))
cmd = CMD_SUSPEND;
else
cmd = CMD_REBOOT;
@@ -91,7 +91,7 @@ static int usage(int rc)
" --halt Halt system, regardless of how the command is called.\n"
" -p, --poweroff Power-off system, regardless of how the command is called.\n"
" --reboot Reboot system, regardless of how the command is called.\n"
"\n", __progname, msg);
"\n", prognm, msg);
return rc;
}
@@ -109,6 +109,7 @@ int main(int argc, char *argv[])
};
/* Initial command taken from program name */
progname(argv[0]);
translate();
while ((c = getopt_long(argc, argv, "h?fHpr", long_options, NULL)) != EOF) {
@@ -191,6 +192,8 @@ int main(int argc, char *argv[])
if (c)
err(1, "Failed signalling init to %s", msg);
else
sleep(2);
return 0;
}
+60 -97
View File
@@ -24,6 +24,8 @@
#include "config.h" /* Generated by configure script */
#include <ctype.h> /* isblank() */
#include <sched.h>
#include <string.h>
#include <sys/wait.h>
#include <net/if.h>
@@ -41,11 +43,8 @@
#include "tty.h"
#include "utmp-api.h"
#define RESPAWN_MAX 10 /* Prevent endless respawn of faulty services. */
#define RESPAWN_MAX 10 /* Prevent endless respawn of faulty services. */
#ifndef INETD_DISABLED
static svc_t *find_inetd_svc (char *path, char *service, char *proto);
#endif
/**
* service_enabled - Should the service run?
@@ -72,16 +71,17 @@ int service_enabled(svc_t *svc)
/**
* service_timeout_cb - libuev callback wrapper for service timeouts
* @w: Watcher
* @arg: Callback argument, from init
* @events: Error, or ready to read/write (N/A for relative timers)
*
* Calls the callback registered with the call to
* service_timeout_after().
*/
static void service_timeout_cb(uev_t *w, void *_svc, int events)
static void service_timeout_cb(uev_t *UNUSED(w), void *arg, int UNUSED(events))
{
svc_t *svc = _svc;
svc_t *svc = arg;
(void)(w);
(void)(events);
svc->timer_cb(svc);
}
@@ -96,15 +96,13 @@ static void service_timeout_cb(uev_t *w, void *_svc, int events)
*
* @return 0 on success, non-zero on error.
*/
static int service_timeout_after(svc_t *svc, int timeout,
void (*cb)(svc_t *svc))
static int service_timeout_after(svc_t *svc, int timeout, void (*cb)(svc_t *svc))
{
if (svc->timer_cb)
return -EBUSY;
svc->timer_cb = cb;
return uev_timer_init(ctx, &svc->timer, service_timeout_cb,
svc, timeout, 0);
return uev_timer_init(ctx, &svc->timer, service_timeout_cb, svc, timeout, 0);
}
/**
@@ -124,26 +122,10 @@ static int service_timeout_cancel(svc_t *svc)
err = uev_timer_stop(&svc->timer);
svc->timer_cb = NULL;
return err;
}
/**
* service_stop_is_done - Have all stopped services been collected?
*
* Returns:
* 1, if all stopped services have been collected. 0 otherwise.
*/
int service_stop_is_done(void)
{
svc_t *svc;
for (svc = svc_iterator(1); svc; svc = svc_iterator(0))
if (svc->state == SVC_STOPPING_STATE)
return 0;
return 1;
}
static int is_norespawn(void)
{
return sig_stopped() ||
@@ -204,7 +186,7 @@ static int service_start(svc_t *svc)
/* Declare we're waiting for svc to create its pidfile */
svc_starting(svc);
/* Block sigchild while forking. */
/* Block SIGCHLD while forking. */
sigemptyset(&nmask);
sigaddset(&nmask, SIGCHLD);
sigprocmask(SIG_BLOCK, &nmask, &omask);
@@ -486,6 +468,20 @@ void service_reload_dynamic(void)
*/
void service_runlevel(int newlevel)
{
if (newlevel == 0 || newlevel == 6) {
/* If we enabled terse mode at boot, restore to previous setting at shutdown */
if (quiet) {
silent = SILENT_MODE;
if (!silent) {
sched_yield();
fputs("\n", stderr);
}
}
/* Call all shutdown hooks before rebooting... */
plugin_run_hooks(HOOK_SHUTDOWN);
}
sm_set_runlevel(&sm, newlevel);
sm_step(&sm);
}
@@ -564,6 +560,9 @@ int service_register(int type, char *line, time_t mtime, char *username)
if (desc) {
*desc = 0;
desc += 3;
while (*desc && isblank(*desc))
desc++;
}
cmd = strtok(line, " ");
@@ -634,7 +633,7 @@ int service_register(int type, char *line, time_t mtime, char *username)
}
/* Check if known inetd, then add ifnames for filtering only. */
svc = find_inetd_svc(cmd, service, proto);
svc = inetd_find_svc(cmd, service, proto);
if (svc)
goto inetd_setup;
@@ -701,7 +700,7 @@ recreate:
name = plugin->name;
if (inetd_new(&svc->inetd, name, service, proto, forking, svc)) {
_e("Failed registering new inetd service %s", service);
_e("Failed registering new inetd service %s/%s", service, proto);
return svc_del(svc);
}
@@ -724,6 +723,7 @@ recreate:
/* New, recently modified or unchanged ... used on reload. */
svc_check_dirty(svc, mtime);
return 0;
}
@@ -772,8 +772,9 @@ void service_monitor(pid_t lost)
static void service_retry(svc_t *svc)
{
int *restart_counter = (int *)&svc->restart_counter;
int timeout;
int *restart_counter = (int *)&svc->restart_counter;
service_timeout_cancel(svc);
if (svc->state != SVC_HALTED_STATE ||
@@ -785,7 +786,7 @@ static void service_retry(svc_t *svc)
if (*restart_counter >= RESPAWN_MAX) {
_e("%s keeps crashing, not restarting", svc->desc);
svc->block = SVC_BLOCK_CRASHING;
svc_crashing(svc);
*restart_counter = 0;
service_step(svc);
return;
@@ -793,16 +794,13 @@ static void service_retry(svc_t *svc)
(*restart_counter)++;
_d("%s crashed, trying to start it again, attempt %d",
svc->desc, *restart_counter);
svc->block = SVC_BLOCK_NONE;
_d("%s crashed, trying to start it again, attempt %d", svc->desc, *restart_counter);
svc_unblock(svc);
service_step(svc);
/* Wait 2s for the first 5 respawns, then back off to 5s */
timeout = ((*restart_counter) <= (RESPAWN_MAX / 2)) ? 2000 : 5000;
service_timeout_after(svc, timeout, service_retry);
return;
}
static void svc_set_state(svc_t *svc, svc_state_t new)
@@ -820,14 +818,11 @@ static void svc_set_state(svc_t *svc, svc_state_t new)
void service_step(svc_t *svc)
{
/* These fields are marked as const in svc_t, only this
* function is allowed to modify them */
int err;
int *restart_counter = (int *)&svc->restart_counter;
svc_cmd_t enabled;
svc_state_t old_state;
cond_state_t cond;
int err;
restart:
old_state = svc->state;
@@ -837,7 +832,7 @@ restart:
svc_status(svc), enabled ? "en" : "dis", svc_dirtystr(svc),
condstr(cond_get_agg(svc->cond)));
switch(svc->state) {
switch (svc->state) {
case SVC_HALTED_STATE:
if (enabled)
svc_set_state(svc, SVC_READY_STATE);
@@ -846,7 +841,7 @@ restart:
case SVC_DONE_STATE:
#ifndef INETD_DISABLED
if (svc_is_inetd_conn(svc)) {
if (svc_is_busy(svc)) {
if (svc_is_busy(svc->inetd.svc)) {
svc_unblock(svc->inetd.svc);
service_step(svc->inetd.svc);
}
@@ -899,23 +894,7 @@ restart:
}
svc_mark_clean(svc);
switch (svc->type) {
case SVC_TYPE_INETD:
case SVC_TYPE_SERVICE:
svc_set_state(svc, SVC_RUNNING_STATE);
break;
case SVC_TYPE_INETD_CONN:
case SVC_TYPE_TASK:
case SVC_TYPE_RUN:
svc_set_state(svc, SVC_STOPPING_STATE);
break;
default:
_e("unknown service type %d", svc->type);
break;
}
svc_set_state(svc, SVC_RUNNING_STATE);
}
break;
@@ -926,15 +905,25 @@ restart:
break;
}
if (!svc->pid && !svc_is_inetd(svc)) {
svc->block = SVC_BLOCK_RESTARTING;
svc_set_state(svc, SVC_HALTED_STATE);
if (!svc->pid) {
if (svc_is_daemon(svc)) {
svc_restarting(svc);
svc_set_state(svc, SVC_HALTED_STATE);
/* Restart directly after the first crash,
* then retry after 2s. */
_d("delayed restart of %s", svc->desc);
service_timeout_after(svc, 1, service_retry);
break;
/*
* Restart directly after the first crash,
* then retry after 2 sec
*/
_d("delayed restart of %s", svc->desc);
service_timeout_after(svc, 1, service_retry);
break;
}
/* Collected inetd connection, drive it to stopping */
if (svc_is_inetd_conn(svc)) {
svc_set_state(svc, SVC_STOPPING_STATE);
break;
}
}
cond = cond_get_agg(svc->cond);
@@ -1007,35 +996,9 @@ restart:
void service_step_all(int types)
{
svc_t *svc;
for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) {
if (!(svc->type & types))
continue;
service_step(svc);
}
svc_foreach_type(types, service_step);
}
#ifndef INETD_DISABLED
static svc_t *find_inetd_svc(char *path, char *service, char *proto)
{
svc_t *svc;
for (svc = svc_inetd_iterator(1); svc; svc = svc_inetd_iterator(0)) {
if (strncmp(path, svc->cmd, strlen(svc->cmd)))
continue;
if (inetd_match(&svc->inetd, service, proto)) {
_d("Found a matching inetd svc for %s %s %s", path, service, proto);
return svc;
}
}
return NULL;
}
#endif
/**
* Local Variables:
* indent-tabs-mode: t
+2 -4
View File
@@ -34,10 +34,8 @@ int service_enabled (svc_t *svc);
void service_reload_dynamic (void);
void service_step(svc_t *svc);
void service_step_all(int types);
int service_stop_is_done(void);
void service_step (svc_t *svc);
void service_step_all (int types);
#endif /* FINIT_SERVICE_H_ */
+79 -38
View File
@@ -64,7 +64,7 @@
* Finit currently forwards this to SIGUSR2.
*/
#include <sched.h>
#include <dirent.h>
#include <string.h> /* strerror() */
#include <sys/reboot.h>
#include <sys/wait.h>
@@ -80,16 +80,64 @@
#include "service.h"
#include "utmp-api.h"
/*
* Old-style SysV shutdown sends a setenv cmd INIT_HALT with "=HALT",
* "=POWERDOWN", or "" to cancel shutdown, before requesting change to
* runlevel 6 over the /dev/initctl FIFO. See plugins/initctl.c
*/
shutop_t halt = SHUT_DEFAULT;
static int stopped = 0;
static uev_t sigterm_watcher, sigusr1_watcher, sigusr2_watcher;
static uev_t sighup_watcher, sigint_watcher, sigpwr_watcher;
static uev_t sigchld_watcher, sigsegv_watcher;
static uev_t sigchld_watcher;
static uev_t sigstop_watcher, sigtstp_watcher, sigcont_watcher;
void mdadm_wait(void);
void unmount_tmpfs(void);
void unmount_regular(void);
/*
* Kernel threads have no cmdline so fgets() returns NULL for them. We
* also skip "special" processes, e.g. mdadm/mdmon or watchdogd that must
* not be stopped here, for various reasons.
*
* https://www.freedesktop.org/wiki/Software/systemd/RootStorageDaemons/
*/
void do_kill(int signo)
{
DIR *dirp;
dirp = opendir("/proc");
if (dirp) {
struct dirent *d;
while ((d = readdir(dirp))) {
int pid;
FILE *fp;
char file[80] = "";
if (d->d_type != DT_DIR)
continue;
pid = atoi(d->d_name);
if (!pid)
continue;
snprintf(file, sizeof(file), "/proc/%s/cmdline", d->d_name);
fp = fopen(file, "r");
if (!fp)
continue;
if (fgets(file, sizeof(file), fp)) {
if (file[0] != '@')
kill(pid, signo);
}
fclose(fp);
}
closedir(dirp);
}
}
void do_shutdown(shutop_t op)
{
@@ -98,30 +146,16 @@ void do_shutdown(shutop_t op)
if (sdown)
run_interactive(sdown, "Calling shutdown hook: %s", sdown);
/* If we enabled terse mode at boot, restore to previous setting at shutdown */
if (quiet) {
silent = SILENT_MODE;
if (!silent) {
sched_yield();
fputs("\n", stderr);
}
}
/* Call all shutdown hooks before rebooting... */
plugin_run_hooks(HOOK_SHUTDOWN);
/* Update UTMP db */
utmp_set_halt();
/* Here is where we signal watchdogd to do a forced reset for us */
_d("Sending SIGTERM to all processes");
kill(-1, SIGTERM);
/* Wait for WDT to timeout, should be no more than ~1 sec. */
/*
* Tell all remaining non-monitored processes to exit, give them
* some time to exit gracefully, 2 sec is customary.
*/
do_kill(SIGTERM);
do_sleep(2);
_d("Sending SIGKILL to remaining processes");
kill(-1, SIGKILL);
do_kill(SIGKILL);
/* Exit plugins and API gracefully */
plugin_exit();
@@ -152,6 +186,7 @@ void do_shutdown(shutop_t op)
unmount_regular();
/* We sit on / so we must remount it ro, try all the things! */
sync();
run("/bin/mount -n -o remount,ro -t dummytype dummydev /");
run("/bin/mount -n -o remount,ro dummydev /");
run("/bin/mount -n -o remount,ro /");
@@ -159,6 +194,15 @@ void do_shutdown(shutop_t op)
/* Call mdadm to mark any RAID array(s) as clean before halting. */
mdadm_wait();
/* Wait here until the WDT reboots, or timeout */
if (wdogpid) {
int timeout = 10;
print(kill(wdogpid, SIGPWR) == 1, "Pending watchdog reboot");
while (timeout--)
do_sleep(1);
}
_d("%s", op == SHUT_REBOOT ? "Rebooting" : "Halting");
if (op == SHUT_REBOOT)
reboot(RB_AUTOBOOT);
@@ -175,6 +219,7 @@ void do_shutdown(shutop_t op)
*/
static void sighup_cb(uev_t *UNUSED(w), void *UNUSED(arg), int UNUSED(events))
{
_d("...");
/* INIT_CMD_RELOAD: 'init q', 'initctl reload', and SIGHUP */
service_reload_dynamic();
}
@@ -184,7 +229,9 @@ static void sighup_cb(uev_t *UNUSED(w), void *UNUSED(arg), int UNUSED(events))
*/
static void sigint_cb(uev_t *UNUSED(w), void *UNUSED(arg), int UNUSED(events))
{
do_shutdown(SHUT_REBOOT);
_d("...");
halt = SHUT_REBOOT;
service_runlevel(6);
}
/*
@@ -192,7 +239,9 @@ static void sigint_cb(uev_t *UNUSED(w), void *UNUSED(arg), int UNUSED(events))
*/
static void sigusr1_cb(uev_t *UNUSED(w), void *UNUSED(arg), int UNUSED(events))
{
do_shutdown(SHUT_HALT);
_d("...");
halt = SHUT_HALT;
service_runlevel(0);
}
/*
@@ -200,7 +249,9 @@ static void sigusr1_cb(uev_t *UNUSED(w), void *UNUSED(arg), int UNUSED(events))
*/
static void sigusr2_cb(uev_t *UNUSED(w), void *UNUSED(arg), int UNUSED(events))
{
do_shutdown(SHUT_OFF);
_d("...");
halt = SHUT_OFF;
service_runlevel(0);
}
/*
@@ -208,7 +259,9 @@ static void sigusr2_cb(uev_t *UNUSED(w), void *UNUSED(arg), int UNUSED(events))
*/
static void sigterm_cb(uev_t *UNUSED(w), void *UNUSED(arg), int UNUSED(events))
{
do_shutdown(SHUT_REBOOT);
_d("...");
halt = SHUT_REBOOT;
service_runlevel(6);
}
/*
@@ -228,15 +281,6 @@ static void sigchld_cb(uev_t *UNUSED(w), void *UNUSED(arg), int UNUSED(events))
} while (pid > 0);
}
/*
* SIGSEGV: mostly if service callbacks segfault
*/
static void sigsegv_cb(uev_t *UNUSED(w), void *UNUSED(arg), int UNUSED(events))
{
_e("PID %d caused a segfault!\n", getpid());
exit(-1);
}
/*
* SIGSTOP/SIGTSTP: Paused by user or netflash
*/
@@ -340,9 +384,6 @@ void sig_setup(uev_ctx_t *ctx)
/* After initial bootstrap of Finit we call the service monitor to reap children */
uev_signal_init(ctx, &sigchld_watcher, sigchld_cb, NULL, SIGCHLD);
/* Trap SIGSEGV in case service callbacks crash */
uev_signal_init(ctx, &sigsegv_watcher, sigsegv_cb, NULL, SIGSEGV);
/* Stopping init is a bit tricky. */
uev_signal_init(ctx, &sigstop_watcher, sigstop_cb, NULL, SIGSTOP);
uev_signal_init(ctx, &sigtstp_watcher, sigstop_cb, NULL, SIGTSTP);
+2
View File
@@ -66,6 +66,8 @@ typedef enum {
SHUT_REBOOT
} shutop_t;
extern shutop_t halt;
void do_shutdown (shutop_t op);
int sig_stopped (void);
void sig_init (void);
+16 -15
View File
@@ -127,6 +127,12 @@ restart:
_d("Setting new runlevel --> %d <-- previous %d", runlevel, prevlevel);
runlevel_set(prevlevel, runlevel);
/* Disable login in single-user mode as well as shutdown/reboot */
if (runlevel == 1 || runlevel == 0 || runlevel == 6)
touch("/etc/nologin");
else
erase("/etc/nologin");
/* Make sure to (re)load all *.conf in /etc/finit.d/ */
conf_reload_dynamic();
@@ -140,7 +146,7 @@ restart:
case SM_RUNLEVEL_WAIT_STATE:
/* Need to wait for any services to stop? If so, exit early
* and perform second stage from service_monitor later. */
if (!service_stop_is_done())
if (!svc_stop_completed())
break;
/* Prev runlevel services stopped, call hooks before starting new runlevel ... */
@@ -154,19 +160,14 @@ restart:
/* Cleanup stale services */
svc_clean_dynamic(service_unregister);
/* Disable login in single-user mode as well as shutdown/reboot */
if (runlevel == 1 || runlevel == 0 || runlevel == 6)
touch("/etc/nologin");
else
erase("/etc/nologin");
if (0 == runlevel) {
do_shutdown(SHUT_OFF);
sm->state = SM_RUNNING_STATE;
break;
}
if (6 == runlevel) {
do_shutdown(SHUT_REBOOT);
/*
* "I've seen things you people wouldn't believe. Attack ships on fire off
* the shoulder of Orion. I watched C-beams glitter in the dark near the
* Tannhäuser Gate. All those .. moments .. will be lost in time, like
* tears ... in ... rain."
*/
if (runlevel == 0 || runlevel == 6) {
do_shutdown(halt);
sm->state = SM_RUNNING_STATE;
break;
}
@@ -195,7 +196,7 @@ restart:
case SM_RELOAD_WAIT_STATE:
/* Need to wait for any services to stop? If so, exit early
* and perform second stage from service_monitor later. */
if (!service_stop_is_done())
if (!svc_stop_completed())
break;
sm->in_teardown = 0;
+39 -2
View File
@@ -24,7 +24,6 @@
#include <stdlib.h>
#include <strings.h>
#include <lite/lite.h>
#include "finit.h"
#include "svc.h"
@@ -261,6 +260,44 @@ void svc_foreach_dynamic(void (*cb)(svc_t *))
}
/**
* svc_foreach_type - Run a callback for each matching type
* @types: Mask of service types
* @cb: Callback to run for each matching type
*/
void svc_foreach_type(int types, void (*cb)(svc_t *))
{
svc_t *svc;
if (!cb)
return;
for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) {
if (!(svc->type & types))
continue;
cb(svc);
}
}
/**
* svc_stop_completed - Have all stopped services been collected?
*
* Returns:
* 1, if all stopped services have been collected. 0 otherwise.
*/
int svc_stop_completed(void)
{
svc_t *svc;
for (svc = svc_iterator(1); svc; svc = svc_iterator(0))
if (svc->state == SVC_STOPPING_STATE)
return 0;
return 1;
}
/**
* svc_find - Find a service object by its full path name
* @cmd: Full path name, e.g., /sbin/syslogd
@@ -441,7 +478,7 @@ char *svc_status(svc_t *svc)
case SVC_BLOCK_USER:
return "blocked";
case SVC_BLOCK_INETD_BUSY:
case SVC_BLOCK_BUSY:
return "busy";
case SVC_BLOCK_RESTARTING:
+11 -5
View File
@@ -60,7 +60,7 @@ typedef enum {
SVC_BLOCK_MISSING,
SVC_BLOCK_CRASHING,
SVC_BLOCK_USER,
SVC_BLOCK_INETD_BUSY,
SVC_BLOCK_BUSY,
SVC_BLOCK_RESTARTING,
} svc_block_t;
@@ -114,8 +114,10 @@ typedef struct svc {
char args[MAX_NUM_SVC_ARGS][MAX_ARG_LEN];
char desc[MAX_STR_LEN];
/* Used to forcefully kill services that won't shutdown on
* termination and to delay restarts of crashing services. */
/*
* Used to forcefully kill services that won't shutdown on
* termination and to delay restarts of crashing services.
*/
uev_t timer;
void (*timer_cb)(struct svc *svc);
} svc_t;
@@ -153,6 +155,9 @@ svc_t *svc_job_iterator (int first, int job);
void svc_foreach (void (*cb)(svc_t *));
void svc_foreach_dynamic (void (*cb)(svc_t *));
void svc_foreach_type (int types, void (*cb)(svc_t *));
int svc_stop_completed (void);
void svc_mark_dynamic (void);
void svc_check_dirty (svc_t *svc, time_t mtime);
@@ -183,11 +188,12 @@ static inline int svc_is_inetd_conn(svc_t *svc) { return svc && SVC_TYPE_INETD_C
static inline int svc_is_daemon (svc_t *svc) { return svc && SVC_TYPE_SERVICE == svc->type; }
static inline int svc_is_blocked (svc_t *svc) { return svc->block != SVC_BLOCK_NONE; }
static inline int svc_is_busy (svc_t *svc) { return svc->block == SVC_BLOCK_INETD_BUSY; }
static inline int svc_is_busy (svc_t *svc) { return svc->block == SVC_BLOCK_BUSY; }
static inline void svc_unblock (svc_t *svc) { svc->block = SVC_BLOCK_NONE; }
static inline void svc_block (svc_t *svc) { svc->block = SVC_BLOCK_USER; }
static inline void svc_busy (svc_t *svc) { svc->block = SVC_BLOCK_INETD_BUSY; }
static inline void svc_busy (svc_t *svc) { svc->block = SVC_BLOCK_BUSY; }
static inline void svc_missing (svc_t *svc) { svc->block = SVC_BLOCK_MISSING; }
static inline void svc_restarting (svc_t *svc) { svc->block = SVC_BLOCK_RESTARTING; }
static inline void svc_crashing (svc_t *svc) { svc->block = SVC_BLOCK_CRASHING; }
#endif /* FINIT_SVC_H_ */
+67 -3
View File
@@ -23,6 +23,8 @@
*/
#include <signal.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <lite/lite.h>
@@ -33,7 +35,10 @@
#include "tty.h"
#include "utmp-api.h"
LIST_HEAD(, tty_node) tty_list = LIST_HEAD_INITIALIZER();
#ifdef FALLBACK_SHELL
static pid_t fallback = 0;
#endif
static LIST_HEAD(, tty_node) tty_list = LIST_HEAD_INITIALIZER();
/* tty [!1-9,S] <DEV> [BAUD[,BAUD,...]] [TERM] */
@@ -118,6 +123,19 @@ size_t tty_num(void)
return num;
}
size_t tty_num_active(void)
{
size_t num = 0;
tty_node_t *entry;
LIST_FOREACH(entry, &tty_list, link) {
if (entry->data.pid)
num++;
}
return num;
}
tty_node_t *tty_find_by_pid(pid_t pid)
{
tty_node_t *entry;
@@ -195,13 +213,56 @@ int tty_enabled(finit_tty_t *tty, int runlevel)
return 0;
}
/* TTY monitor, called by service_monitor() */
/*
* Fallback shell if no TTYs are active
*/
int tty_fallback(pid_t lost)
{
#ifdef FALLBACK_SHELL
if (lost == 1) {
if (fallback) {
_d("Stopping fallback shell");
kill(fallback, SIGKILL);
fallback = 0;
}
return 0;
}
if (fallback != lost || tty_num_active()) {
_d("Not starting fallback (%d) shell, lost pid %d", fallback, lost);
return 0;
}
_d("Starting fallback shell");
fallback = fork();
if (fallback)
return 1;
/*
* Become session leader and set controlling TTY
* to enable Ctrl-C and job control in shell.
*/
setsid();
ioctl(STDIN_FILENO, TIOCSCTTY, 1);
_exit(execl(_PATH_BSHELL, _PATH_BSHELL, NULL));
#else
(void)lost;
#endif /* FALLBACK_SHELL */
return 0;
}
/*
* TTY monitor, called by service_monitor()
*/
int tty_respawn(pid_t pid)
{
tty_node_t *entry = tty_find_by_pid(pid);
if (!entry)
return 0;
return tty_fallback(pid);
/* Set DEAD_PROCESS UTMP entry */
utmp_set_dead(pid);
@@ -228,6 +289,9 @@ void tty_runlevel(int runlevel)
else
tty_start(&entry->data);
}
/* Start fallback shell if enabled && no TTYs */
tty_fallback(tty_num_active() > 0 ? 1 : 0);
}
/**
+1
View File
@@ -49,6 +49,7 @@ typedef struct tty_node {
int tty_register (char *line);
tty_node_t *tty_find (char *dev);
size_t tty_num (void);
size_t tty_num_active (void);
tty_node_t *tty_find_by_pid (pid_t pid);
void tty_start (finit_tty_t *tty);
void tty_stop (finit_tty_t *tty);
+44
View File
@@ -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:
*/
+38
View File
@@ -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:
*/
+5
View File
@@ -21,6 +21,9 @@
* THE SOFTWARE.
*/
#ifndef FINIT_UTMP_API_H_
#define FINIT_UTMP_API_H_
int utmp_set (int type, int pid, char *line, char *id, char *user);
int utmp_set_boot (void);
int utmp_set_halt (void);
@@ -30,6 +33,8 @@ int utmp_set_dead (int pid);
int utmp_set_runlevel(int pre, int now);
int utmp_show (char *file);
#endif /* FINIT_UTMP_API_H_ */
/**
* Local Variables:
* indent-tabs-mode: t
+135
View File
@@ -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
View File
@@ -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:
*/