Compare commits

..
836 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
Joachim Nilsson dd566acfd2 Update ChangeLog and bump version for v3.0-rc1
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-09-14 00:04:00 +02:00
Joachim Nilsson 5c56f5c5a7 Fix make distcheck: Add missing header file to build deps.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-09-13 23:02:01 +02:00
Joachim Nilsson 7ab963a576 Remove eXecutable flag from source files
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-09-13 23:00:06 +02:00
Joachim Nilsson 73d462c847 utmp_set(): Fix uninitialized return value
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-09-13 22:47:16 +02:00
Joachim Nilsson 56e94a4e4a Merge branch 'westermo-usr/wkz/timeout'
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-09-13 21:56:39 +02:00
Joachim Nilsson 51830e0f5b Merge branch 'usr/wkz/timeout' of https://github.com/westermo/finit into westermo-usr/wkz/timeout 2016-09-13 21:53:26 +02:00
Joachim Nilsson 85115eca62 Fix invalid ptr assignment for --enable-static builds
Also changes the default to set $HOME to / instead of nothing.  This can
of course be improved immensely.  Pull requests always welcome ;-)

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-09-13 21:41:36 +02:00
Joachim Nilsson 659ff9962e Fallback (unused) PLUGIN_PATH for --enable-static builds
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-09-13 21:41:11 +02:00
Joachim Nilsson 9436c8b73c Minor whitespace cleanup
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-09-13 21:25:40 +02:00
Joachim Nilsson 5a3397419f Remove support for service callback plugins
This patch removes the now heavily outdated (and non-working) support
for callback plugins.  I.e. plugins that attach themselves to services
listed in /etc/finit.conf and can be queried to determine if a service
should be started or stopped.

The Finit3 support for adding/removing services at runtime with plain
text *.conf files in /etc/finit.d and `initctl reload`, this old, and
rather cumbersome service callback feature, is not longer supported.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-09-13 21:20:06 +02:00
Tobias Waldekranz 10b72f1d7f service: kill stubborn services, wait before restart
Add support for registering callbacks to be called after a given
timeout.

Use this to implement forceful termination of services that refuse to
terminate upon receiving a SIGTERM. If the service PID is not collected
within 3 seconds, send a SIGKILL to it.

Also, rework restarting of crashing services. When a service crashes for
the first time, try to restart it immediately. If it crashes again, wait
a few seconds before trying again. Just as before, if it continues to
crash, block the service.
2016-09-13 20:26:28 +02:00
Joachim Nilsson 6b237b7b00 Refactor abstraction of svc blocking state
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-09-12 19:30:48 +02:00
Joachim Nilsson b4f385d2e0 Only log to stderr if opening /dev/kmsg failed for early logging
This patch prevents double critical/error messages from being printed on
the console when there is no syslog daemon running yet.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-09-08 17:11:52 +02:00
Joachim Nilsson 4b4572de4d Minor refactor of error/debug messages
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-09-08 17:11:27 +02:00
Joachim Nilsson 19b81cf434 Fix #40, #39: initctl plugin started too early, before /run FS existed
Delay setup of initctl plugin to after the base filesystems are up and
after the bootmisc plugin has run.

This patch factors out the I/O initialization of plugins so it does not
have to run when plugins are loaded.  Instead, plugins can now call this
API to register an I/O callback when they are ready.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-09-08 12:58:28 +02:00
Joachim Nilsson 3023433def Do not write DEAD_PROCESS records to UTMP, only WTMP
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-09-08 12:51:32 +02:00
Joachim Nilsson 49968c188b UTMP: Make sure to use the full width of all UTMP fields
In UTMP a terminating zero in string fields is optional, so we need to
take that into account when preparing entrys.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-09-08 12:51:20 +02:00
Joachim Nilsson 2499405b27 Misc. whitespace fixes, and comment
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-09-06 00:08:40 +02:00
Joachim Nilsson 9fc1f50678 bootmisc: The getgroup() API returns int not gid_t
Must use int to check for error code (-1) from getgroup() API.
Found by Coverity Scan.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-09-05 00:55:21 +02:00
Joachim Nilsson b1d709ba22 reboot: CMD_SUSPEND not handled atm by Finit
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-09-05 00:54:52 +02:00
Joachim Nilsson 5ddc35d387 echo: Mark callback argument as unused
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-09-05 00:54:29 +02:00
Joachim Nilsson 50632f941b Fix missing initializer for array end marker
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-09-05 00:46:15 +02:00
Joachim Nilsson 7b215e4fd4 Update dependencies for libuEv and libite (-lite)
This patch makes Finit require libuEv v1.4.2, a minor bugfix update, and
libite (-lite) v1.8.2, which is quite a bit more than just a few bug
fixes.  The most relevant fixes are the removal of implicit logging for
touch(), makedir(), makefifo(), and erase() inline functions.  The
release also removed implicit logging to stderr on error, as well as a
a few build fixes for running on musl libc.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-09-05 00:24:55 +02:00
Joachim Nilsson bb7208c591 bootmisc: Check return value from chmod() API
Found by Coverity Scan.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-09-04 23:23:37 +02:00
Joachim Nilsson bb0505f57c bootmisc: Check return value from getgroup() API
Found by Coverity Scan.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-09-04 23:13:51 +02:00
Joachim Nilsson 4aa569de44 Fix descriptor leak in getty()
Found by Coverity Scan.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-09-04 23:03:42 +02:00
Joachim Nilsson 512a07a25c Fix resource leak if tty_register() fails (minor)
Found by Coverity Scan.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-09-04 22:55:21 +02:00
Joachim Nilsson 8cfd11c909 Use safe string copy using strlcpy()
Fixes issues with buffers not being NUL terminated properly.
Found by Coverity Scan.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-09-04 22:52:34 +02:00
Joachim Nilsson c3adf3bf51 Bump version to v3.0-beta2 no more feature expected
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-09-04 20:48:49 +02:00
Joachim Nilsson 3ca28e765d Fix #38: Add --enable-emergency-shell fallback debug mode
This patch adds a very special debug mode to Finit.  With this feature
enabled the actual duties of PID 1 is forked off early to a child.  If
that child ever dies, usually due to a SIGSEGV, this wakes up the real
PID 1 which lauches a debug shell on the console.

Remember to disable 'quiet' and enable '--debug' on the kernel command
line to get all the debug logs -- which these days goes into the kernel
log in /dev/kmsg -- simply `cat /dev/kmsg` and use Ctrl-C to get the
shell prompt back.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-09-04 20:27:12 +02:00
Joachim Nilsson 79207dcb22 Support for starting finit-getty with a given user
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-09-04 20:02:59 +02:00
Joachim Nilsson 47f3e2ca04 Clarify what --disable-quiet actually does
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-09-04 18:40:58 +02:00
Joachim Nilsson 2e7bee9f84 Fix #36: Don't delete inetd on failed registration
This patch fixes to root cause to issue #36, reported by Markus Svilans.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-09-04 17:22:50 +02:00
Joachim Nilsson 2681e4c01a Add early logging support to /dev/kmsg
Very early, before syslogd has started, we have traditionally been
forced to use stdout/stderr for debug, warning and error messages.

With this patch we can now rely on /dev/kmsg to preserve all logs
from early Finit problems.  When syslogd/klogd starts up they read
/dev/kmsg and copy logs to /var/log/* files.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-09-04 17:19:06 +02:00
Joachim Nilsson 56a3f6882b Improve inetd service registration
- Refactor getent() for improved separation and readability
- Warn and exit if /etc/protocols or /etc/services is missing

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-09-04 17:17:22 +02:00
Joachim Nilsson 88d8ab67c9 Add _w() for developer warning logs
Adjust debug levels slightly and add _w() macro for LOG_WARNING,
useful when having /dev/kmsg as backend.  The latter outputs any
log <= LOG_ERR to console as well.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-09-04 17:15:41 +02:00
Joachim Nilsson 74eb2bf4d2 initctl: Add dependency on bootmisc
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-09-04 17:13:38 +02:00
Joachim Nilsson b3fb9ab3ed Fix placement of newline for early debug
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-09-04 16:10:23 +02:00
Markus Svilans 308ae609c4 Fix #35: Build fails with --disable-inetd
This patch fixes a build problem when configured without inetd support.

Signed-off-by: Markus Svilans <msvilans@aeonyx.ca>
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-08-31 16:30:04 +02:00
Joachim Nilsson e3783e8bac README: Fix spelling error
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-08-26 21:36:04 +02:00
Joachim Nilsson 002b24fbc2 README: Improve ingress
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-08-26 21:34:36 +02:00
Joachim Nilsson 3f71ed352d initctl: Remove confusing/wrong debug message
The 's' runlevel after boot is the traditional single-user rescue mode.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-08-24 22:08:46 +02:00
Joachim Nilsson f7305c36b8 reboot: Clarify -f, --force option in usage text
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-08-24 22:08:26 +02:00
Joachim Nilsson 8bcecd474b Refresh telinit client
- Add support for SysV init setenv to activate poweroff
- Update help text considerably to be more helpful

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-08-24 20:26:09 +02:00
Joachim Nilsson a9a7b08021 Disable login also in shutdown/reboot
Disable login in single-user mode as well as shutdown/reboot

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-08-24 19:27:23 +02:00
Joachim Nilsson 62cb683af0 initctl: Show WTMP log first and active UTMP last
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-08-23 16:35:44 +02:00
Joachim Nilsson 65e44dc88f UTMP: By convention, getty has user "LOGIN"
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-08-23 07:49:32 +02:00
Joachim Nilsson 54467d4467 configure: Minor whitespace changes
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-08-22 12:39:51 +02:00
Joachim Nilsson cfa258e7f2 UTMP: Log to /var/log/wtmp as well as /run/utmp
The UTMP db tracks currently logged in users and WTMP is an audit trail
of all user logins and logouts, as well as runlevel changes and reboot.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-08-22 12:36:17 +02:00
Joachim Nilsson 574760df13 UTMP: Set LOGIN_PROCESS for built-in getty
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-08-22 12:36:03 +02:00
Joachim Nilsson c2ec25efd3 Use logit() for _d() and _e() messages as well
The new logit() function takes care to print to stderr if syslogd has
not yet started.  The _d(), _e(), and _pe() macros have an additional
requirement: to always print on stderr.

After the boot we also want to see what happned during, so this patch
simply adds syslog() support to _d(), _e(), and _pe().

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-08-18 01:48:41 +02:00
Joachim Nilsson d670e7d3e8 Clean up logging, log to stderr until syslogd has started
This patch removes internal logging macros and adds support for logging
to stderr until a syslogd is up and running, i.e. /dev/log appears.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-08-18 01:18:31 +02:00
Joachim Nilsson 77561b6071 Replace old ANSI helper macros with libite/conio.h
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-08-18 00:39:59 +02:00
Joachim Nilsson cec1c64755 Fix build on older (G)LIBC's w/o RB_SW_SUSPEND
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-08-18 00:11:11 +02:00
Joachim Nilsson 5bab329178 UTMP: Only account for getty processes
This patch removes accounting for all processes to instead implement the
traditional SysV getty accounting.  (Telnet/SSH et al maintain their own
accounding for UTMP.)

TODO: WTMP support

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-08-17 18:43:49 +02:00
Joachim Nilsson b6bf8bf518 Fix GRUB menu entry generation for Debian & Ubuntu
This patch fixes the /etc/grub.d/40_custom generation for the Debian
sample so that it properly extracts the UUID For /boot and /

Note: the maintenance free symlinks /vmlinuz and /initrd.img may not
work properly with /boot on a separate partition or disk.  If only
the symlinks where in /boot as well ...

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-08-15 02:26:01 +02:00
Joachim Nilsson 0a21ff5236 Update Alpine configure example
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-08-15 02:25:13 +02:00
Joachim Nilsson 3853061f09 Remove --enable-embedded configure option
Instead of ugly #ifdefs we now probe for mdev or udevd at runtime.  Take
care to check for udev-finalize and location of udevd, it differs a lot
between distros.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-08-15 00:25:07 +02:00
Joachim Nilsson 078982d3ec Initial support for mdadm RAID arrays
This patch adds initial support for handling MD RAID arrays.  Adding
a pass at the very end of the shutdown sequence to signal any external
RAID controller to clear its state before we proceed to halt/reboot.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-08-14 21:26:18 +02:00
Joachim Nilsson f4327910d9 Only unmount non-protected filesystems at shutdown
This patch adds support for a more fine grained approach to what
filesystems are unmounted at shutdown/reboot.  This so we later
can add support for `mdadm --wait-clean --scan`, which relies on
/proc, /sys, and /dev being there before we call reboot().

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-08-14 21:09:15 +02:00
Joachim Nilsson b1fb536468 reboot: Remove sync() is up to user to do that
Also, this code will be refactored soon to be a part of the finit
binary, like telinit, and then we will be called after unmount to
do a forced halt/reboot/poweroff.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-08-14 13:29:58 +02:00
Joachim Nilsson 95cb94cf49 Remember to shift use state machine in sig.c:do_shutdown()
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-08-14 13:26:27 +02:00
Joachim Nilsson e1c0e7fe58 Add install/uninstall for reboot symlinks
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-08-14 13:20:48 +02:00
Joachim Nilsson 9783e120af Fix install/uninstall of Finit symlinks
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-08-14 13:20:27 +02:00
Joachim Nilsson 3ad149fb28 Workaround for uninstalling .so plugins
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-08-14 13:19:35 +02:00
Joachim Nilsson e6430aabc2 Update and remove services script from distribution
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-08-14 13:19:20 +02:00
Joachim Nilsson 2743a49d91 reboot: Add halt/poweroff/suspend and force cmd
This patch is a complete rewrite of the Finit reboot command.  Not only
does it bring it up to speed with the new signal model, but it also adds
new features like poweroff, halt, and suspend -- including a forced mode
that goes for reboot(2) immediately.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-08-14 12:27:52 +02:00
Joachim Nilsson 6f99c1db05 initctl: Add missing signal.h include for older systems, e.g. Travis CI
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-08-11 00:03:20 +02:00
Joachim Nilsson 0eafe8bcd9 initctl: Show error message when trying to signal PID 1 as non-root
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-08-10 21:39:09 +02:00
Joachim Nilsson b01fae03ec Copy all chars of UTMP fields: id, line, and user
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-08-09 20:35:44 +02:00
Joachim Nilsson dbbe6b31b8 UTMP: Fix runlevel regression after refactoring
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-08-09 20:35:03 +02:00
Joachim Nilsson 2718c709aa UTMP: Add support for INIT_PROCESS & DEAD_PROCESS
Services started by Finit are now properly accounted for in UTMP.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-08-09 00:58:00 +02:00
Joachim Nilsson 8c54fde36c Fix D-Bus plugin, remove old #ifdefs
Still TODO, replace `run_interactive()` start of dbus-daemon with a
proper service.  Possibly only service_register() is needed.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-08-09 00:12:47 +02:00
Joachim Nilsson 0d1bc167ff initctl: Fix display of UTMP records, add IP addr
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-08-09 00:12:47 +02:00
Joachim Nilsson f8def336d4 Fix ordering of UTMP events: reboot, then runlevel
This patch fixes the ordering of UTMP events. The first event that is
expected in /var/run/utmp is reboot, next is the runlevel change to
the configured runlevel, e.g. from S --> 2.

Let the bootmisc plugin handle this, it knows when /var/run/utmp has
been created and is writable.  It is not the eact boot time, but close
enough for most usees.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-08-09 00:12:47 +02:00
Joachim Nilsson addc21bdf6 UTMP: Set BOOT_TIME record and add shutdown
This patch adds support for initializing /var/run/utmp with the initial
reboot as well as a shutdown record in the UTMP db.

Also, the run level change now properly records ~ and ~~ as line and id,
respectively, and the kernel release and time of each UTMP record is now
set properly.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-08-08 19:06:35 +02:00
Joachim Nilsson 27899feea0 bootmisc: Add /var/log/btmp 0600 support
The file /var/log/btmp holds bad login attempts and must be created with
0600 perms.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-08-08 00:05:34 +02:00
Joachim Nilsson a016359891 Factor out runlevel handling to new UTMP API
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-08-07 22:36:31 +02:00
Joachim Nilsson 7cdd42195b initctl: Break out UTMP logic to separate file
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-08-07 22:22:42 +02:00
Joachim Nilsson 07f06c8b95 inictl: Enable UTMP dump command
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-08-06 18:51:25 +02:00
Joachim Nilsson 2067fd597f initctl: Raw UTMP dump tool
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-08-06 18:49:22 +02:00
Joachim Nilsson f0318b0df0 Rephrase
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-08-05 17:46:44 +02:00
Joachim Nilsson 508c7b225a Prune completed TODO items
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-08-05 17:45:58 +02:00
Joachim Nilsson 8a79b05a97 Add missing bracket
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-08-05 17:45:25 +02:00
Joachim Nilsson 7b07d5559c Service status 'crashing' --> 'crashed'
Minor coding style cleanup, code simplification, and change service
'crashing' status text to 'crashed' to fit column width.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-08-05 17:43:45 +02:00
Joachim Nilsson 23cdd6e438 Update Debian HowTo with new build.sh script
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-08-05 01:16:35 +02:00
Joachim Nilsson 576cb1075c Boiler plate README for contrib/ section
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-08-05 01:06:23 +02:00
Joachim Nilsson fc74fb110d README: Further simplication of example in ingress
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-08-05 01:06:20 +02:00
Joachim Nilsson baa914e995 initctl: add reboot, halt, and poweroff commands
Simple wrappers for the signals Finit responds to.  Will need complete
rewrite when support for delayed reboot/halt is added.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-08-04 22:45:05 +02:00
Joachim Nilsson 6490735ee9 Remove flux condition emulation, confusing to user
The condition flux state does not work like that, so keeping
this sub-command is only confusing to the user.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-08-04 22:40:20 +02:00
Joachim Nilsson 13159ea99a Mention support for Debian and Alpine early!
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-08-04 00:38:45 +02:00
Joachim Nilsson b9fa0f85a2 Update inline documentation for Debian finit.conf
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-08-03 11:12:56 +02:00
Joachim Nilsson dbbe3cecb3 Debian helper build & install scripts
These scripts help a user to configure, build, and install Finit
correctly on a Debian 8 (Jessie) server install.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-08-03 10:58:45 +02:00
Joachim Nilsson 1a8f1d9604 getfsent(): Read only six fields per line
The fs.fs_type is only for *BSD, we hard-code it to "rw"
in the meantime.  Should be safe in most cases.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-08-02 02:01:51 +02:00
Joachim Nilsson d76ecad517 fsck: Prevent debug during interactive fsck
The debug mode cannot be used in run_interactive() that early, so we
must disable it during the complete fsck run.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-08-02 02:00:01 +02:00
Joachim Nilsson f81750e0b1 fsck: Skip progress, does not work the same with BusyBox fsck
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-08-02 01:59:14 +02:00
Joachim Nilsson 7fc7faf59a fsck: Prevent double-checking filesystems
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-08-02 01:58:41 +02:00
Joachim Nilsson c38b452ac4 Add set/get/endfsent() support for musl libc
This patch adds support for the following /etc/fstab API's on systems
that do not have them, e.g. musl libc on Alpine Linux.

- setfsent()
- getfsent(), and
- endfsent()

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-08-02 00:50:23 +02:00
Joachim Nilsson 7eac88b639 Run fsck earlier and print only first 13 chars
Run fsck much earlier, as soon as we can in fact.

The first 13 characters of the UUID, label or device name should
be sufficient to identify the device, without violating max width
of 78 chars.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-08-01 23:51:11 +02:00
Joachim Nilsson f374f443f4 Allow fsck on UUID= and LABEL= devices
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-08-01 23:38:55 +02:00
Joachim Nilsson d2a5e65862 Support for checking file systems from /etc/fstab
This patch adds support for running fsck on all file systems listed in
/etc/fstab with a passno > 0.  The fsck runs sequentially, starting with
the root fs (passno 1).

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-08-01 18:08:54 +02:00
Joachim Nilsson 501deae4ed Update doc, support sysctl from all the locations!
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-31 10:21:15 +02:00
Joachim Nilsson 2c29893558 Prune old (and now irrelevant) TODO items
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-31 10:16:52 +02:00
Joachim Nilsson a1a7f69349 Update info on getty, no /bin/login included
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-30 16:06:35 +02:00
Joachim Nilsson 8d9fbea551 Micro adjustment
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-30 16:03:32 +02:00
Joachim Nilsson 1d89e1a706 Advertise for new logo ...
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-30 16:02:51 +02:00
Joachim Nilsson 596b7cc413 README: Mention built-in getty
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-30 16:00:31 +02:00
Joachim Nilsson fbed5cd8cb TODO: Timed shutdown/reboot incl. cancellation
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-30 15:55:59 +02:00
Joachim Nilsson 0cb1ce2483 Disable clear screen in getty
Disabled until we decide on config to disable/enable.  It is quite
annoying to not be able to see the boot messages with it on ...

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-30 15:54:37 +02:00
Joachim Nilsson e23b62ffb7 Plugin loader fixes for dep handling and unload
- Plugins without declared name registered with full path + ext
  => Strip path and extension
- Plugins registered with __NAME__ => strip extension
- Do *not* call dlclose() from destructor, must be called by Finit

Also, some minor cleanup and code simplifcation.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-30 15:54:37 +02:00
Joachim Nilsson 94d41e38f8 Close inotify watcher when TTY plugin is unloaded
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-30 15:54:37 +02:00
Joachim Nilsson 42800a1cc8 ALSA plugin: only run if /usr/sbin/alsactl exists
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-30 15:54:37 +02:00
Joachim Nilsson 4cf60b7491 initctl: Add SysV compat support for setenv
- Fix compat INIT_CMD_ defines so Finit clients can talk to SysV init
- Add setenv support, only for INIT_HALT={POWERDOWN,HALT} to runlevel 6

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-30 15:54:37 +02:00
Joachim Nilsson 72a9832662 Remove developer debug of reboot/umount sequence
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-30 15:54:37 +02:00
Joachim Nilsson eeb59eb22b Adopt BusyBox init signal handling for halt/reboot/poweroff
This patch adopts the BusyBox init signals for handling halt, reboot,
and poweroff.  The SIGINT and SIGPWR signals still behave the same as
before, even though they likely will become configurable in a future
release.

Note: the disabling of Ctrl-Alt-Delete (SIGINT) is also removed!

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-29 16:47:38 +02:00
Joachim Nilsson 0df0f019e3 Alpine Linux finit.conf updates
First lessons from Debian, more to come ...

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-29 01:08:48 +02:00
Joachim Nilsson bc7f6f1bc1 Debian HowTo: Minor fixup
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-29 00:22:32 +02:00
Joachim Nilsson 73b807a007 Debian HowTo: Minor reformatting
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-29 00:20:46 +02:00
Joachim Nilsson 62113a0057 New mini HowTo: Finit on Debian Jessie
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-29 00:13:03 +02:00
Joachim Nilsson 968f1bf991 The science of unmounting file systems on Debian
That's maybe a bit unfair.  This patch implements a brief version of
what is really needed to safely unmount all file systems on a modern
Linux distribution.  Yes, it's this insane.  (Who am I kidding, it's
worse!  Just have a look at the ancient scrolls hidden in your /etc!)

Here is where we use the new plugin_exit() and api_exit() API's from an
earlier patch.  Making sure to exit and close any kernel descriptors.
Then follows a bizarre spell cast on leaking descriptors, rebooting in
a child, remounting / as read-only, and a whole slew of other R rated
stuff to prevent mount/umount from returning 32 ...

Stay safe people, use protection always!

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-28 23:48:39 +02:00
Joachim Nilsson 57514130fc Starting service as @user chdir() to their $HOME
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-28 23:48:39 +02:00
Joachim Nilsson 0710fdd2a3 Plugin and API init/exit for conformance
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-28 23:48:39 +02:00
Joachim Nilsson 08e46782e5 Print banner earlier
Thanks to udev we need to do a lot more stuff even earlier these days.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-28 23:48:39 +02:00
Joachim Nilsson b96d8d3055 Handle tabs in finit.conf better
Should probably be extended to handle any non-space blank character.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-28 23:48:38 +02:00
Joachim Nilsson 4ede2a93b2 Change initctl FIFO from /dev/ to /var/run/
FIFOs, PID files, and other non-devices belong in /var/run (or /run
these days), not /dev -- as per FHS.  Compat with Debian SysV init.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-28 23:48:38 +02:00
Joachim Nilsson dd2eb9ce04 Initial contrib/debian support for Jessie
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-28 23:48:38 +02:00
Joachim Nilsson d15633781b TTY: Major overhaul, move to built-in getty
The TTY handling in Finit has always been a bit of a patch work.  This
commit is an attempt at a first cleanup and simplification.

Included is a brand new built-in getty which should work fine on both
virtual and serial consoles.  It is however completely untested on the
latter serial consoles.

Still TODO: add support for /etc/securetty, add support for actually
setting TERM when calling /bin/login.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-28 23:48:38 +02:00
Joachim Nilsson 789354ab40 Improve udev support on non-embedded systems
Embedded Linux systems usually employ BusyBox mdev.  This patch assumes
that all non-embedded systems employ udev.  Adding support for cleaning
up the udev db after the initramfs, or mounting /dev if that not done.
It also runs the udev-finish script at the end.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-27 19:28:42 +02:00
Joachim Nilsson 8002704a5f bootmisc: Create /var/run/network/ for ifupdown
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-27 19:25:50 +02:00
Joachim Nilsson 82853bf0ea Add support for ifupdown 'allow-hotplug' keyword
Look for 'auto' *and* 'allow-hotplug' in /etc/network/interfaces when
bringing up Debian/BusyBox interfaces at boot.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-27 19:25:19 +02:00
Joachim Nilsson bfe9e011bd Remove fallback to /bin/sh if no TTY is defined
If the user specifies no 'tty /dev/ttyN' in finit.conf this code
took upon itself to add a backdoor to the system.  Let's remove
it and rely on the operator deciding what is best practise.

With this patch no getty, or fallback shell, will be started if
no tty line in finit.conf is available.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-27 19:14:36 +02:00
Joachim Nilsson 9416e14074 Minor cleanup and default signals also for getty
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-26 21:13:19 +02:00
Joachim Nilsson 46a58f058a Simplify, simplify, simplify ...
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-26 01:29:31 +02:00
Joachim Nilsson 72a484b639 Break out building and bootstrap to separate files
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-23 00:25:14 +02:00
Joachim Nilsson 82e483d6c7 Start splitting up the README into separate files
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-22 23:31:57 +02:00
Joachim Nilsson dafa50ee42 Add links to dependencies in build section
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-22 23:07:25 +02:00
Joachim Nilsson 2187e05e06 Update build instructions
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-22 22:59:08 +02:00
Joachim Nilsson a4fd058607 Update example finit.conf
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-22 22:58:43 +02:00
Joachim Nilsson c49eb5e10d Replace classic Finit rally car with retro ASCII logo
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-22 22:57:55 +02:00
Joachim Nilsson 01d1dabaae Remove useless hostname debug
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-22 22:44:39 +02:00
Joachim Nilsson a3b0022d66 Minor cleanup and additions
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-22 20:00:13 +02:00
Joachim Nilsson e4d882e99e Fix ToC links and add finit.conf example
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-22 19:29:23 +02:00
Joachim Nilsson 5ef426d424 Link to files
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-22 19:28:14 +02:00
Joachim Nilsson 5ee1b7c322 Name waiting-for-enter to getty process
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-21 20:43:23 +02:00
Joachim Nilsson 0d665f3773 Correct adjustment of initctl show columns
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-21 16:48:29 +02:00
Joachim Nilsson 38619966ee Fix interface bring up message NULL ptr deref
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-21 16:35:57 +02:00
Joachim Nilsson 6380f17d1f Prototype support for /etc/netork/interfaces
This patch adds prototype support for the Debian/Ubuntu/Busybox network
configuration file /etc/netork/interfaces.  If this file exists Finit
will call `ifup` for each (non-commented-out) interface marked `auto`.

With this implementation we block boot until all ifup commands have
returned, which is less than ideal.  A better approach would be to ifup
only loopback and create deferred tasklets to be run in parallel with
the rest of the boot.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-21 16:11:50 +02:00
Joachim Nilsson 42181a3031 Add OpenRC-like support for sysctl.d/*.conf
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-21 15:49:00 +02:00
Joachim Nilsson 77b32ebff0 Update Alpine Linux example config
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-21 15:37:15 +02:00
Joachim Nilsson 97de3ad0bb Slight adjustment, plus 1, to allow 79 char width
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-21 15:15:26 +02:00
Joachim Nilsson 44f8a2666f tty: Always detach from initial TTY and open actual /dev/ttyN
This patch fixes a long standing problem with TTY's.  The original code
tried to workaround a limitation in the console of some embedded systems
that was detrimental on actual TTYs.

As an added benefit, the console specific "Press Enter" prompt for the
console port is now available on all TTYs -- meaning no getty needs to
be started and kept needlessly in the background until it is needed.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-21 14:57:58 +02:00
Joachim Nilsson 4cf5b055cf Adjust max width to 79 chars in text output
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-21 14:28:03 +02:00
Joachim Nilsson 744bb9dd14 Workaround for loopback interface
We never get any NEWLINK message for lo since it as an interface exists
very early.  So we add this workaround when lo comes up so services can
depend on exists for lo as well as for other interfaces.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-21 14:04:37 +02:00
Joachim Nilsson 1edfecdaab Use -v to also dump asserted condition flags in cond show
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-21 13:53:51 +02:00
Joachim Nilsson bc84d66018 Allow conditions for tasklets and runlets as well
The introduction of conditions to Finit only focused on
services (monitored daemons) and not parallell one-shot
tasks or blocking one-shot runs.

This patch enables condition support for 'task' and 'run'
stanzas in both finit.conf and finit.d

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-21 11:47:21 +02:00
Joachim Nilsson 2216923343 Minor whitespace fixes
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-21 11:43:09 +02:00
Joachim Nilsson ac834cfa1c I am the reaper of lost children ...
... but let's keep it quiet, OK?

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-21 01:16:51 +02:00
Joachim Nilsson f191266a33 Add --with-random-seed to enable urandom plugin
By default the urandom plugin will use /var/lib/misc/random-seed across
reboots to seed /dev/urandom at boot.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-21 00:41:23 +02:00
Joachim Nilsson 796275af62 HowTo: Finit on Alpine Linux 3.4
Mini HowTo with config files :)

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-21 00:29:49 +02:00
Joachim Nilsson a7e52914d2 Set a default description for all services
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-21 00:08:56 +02:00
Joachim Nilsson fcfbd57ca8 With 'log' keyword, always log process name
Do not tag log messages with service description, but use process name.
Possibly add :ID later to denote instance if multiple instances exist.

Also, add priority daemon.info log level.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-20 19:59:27 +02:00
Joachim Nilsson 5b81d14e51 x11-common: If restorecon exists, run it
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-20 19:58:42 +02:00
Joachim Nilsson 329af172de Fix default GREET
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-20 19:58:21 +02:00
Joachim Nilsson 33ce1592c1 bootmisc: Create /var/log/wtmp and lastlog too
Set correct permission bits, the utmp group must have write permission.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-20 19:57:39 +02:00
Joachim Nilsson 7a954e3743 Run user network start script cleanly
If user has no start script fall back to set up at least loopback.  This
fixes (at least) a problem on Alpine Linux where `ifup -a` returns error
if `lo` is already up.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-20 18:27:11 +02:00
Joachim Nilsson 48c2937f4f Simplify bootstrap message for rc.local start
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-20 18:24:30 +02:00
Joachim Nilsson 24961eb3ba Minor grammar fix in bootstrap message
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-20 17:30:36 +02:00
Joachim Nilsson aced97c2e6 Handle systems with new /run tmpfs
Modern systems today use a RAM disk for /run and /run/lock, with
symlinks to the FHS locations in /var/run and /var/lock.  See the
following link for details http://lwn.net/Articles/436012/

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-20 17:30:29 +02:00
Joachim Nilsson a67350ebf6 Little bit more careful with init/telinit symlinks
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-19 17:00:40 +02:00
Joachim Nilsson c47a0cd812 Conditionalize 'rlimit rttime', not available yet on musl libc
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-19 15:56:49 +02:00
Joachim Nilsson 67c0d43912 Merge branch 'refactor-readme'
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-18 20:26:11 +02:00
Joachim Nilsson 7b00969f6c Merge remote-tracking branch 'origin/inetd-plugins'
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-18 20:25:36 +02:00
Joachim Nilsson 875080d1e1 Minor update
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-18 17:30:56 +02:00
Joachim Nilsson 1121965167 Do not build inetd plugins if inetd is disabled
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-18 17:30:29 +02:00
Joachim Nilsson 45bdadebb6 Minor cleanup
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-18 17:30:14 +02:00
Joachim Nilsson 7dfdc2395b Add protection against UDP inetd looping attacks
This patch adds protection against a common inetd attack vector wherein
the reply port to UDP inetd services is forged to an internal inetd
service port.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-18 17:27:37 +02:00
Joachim Nilsson 5723b2e75b Refactor RFC 868, time protocol plugin
- Always do a dummy read to get peer address.
- Refactor to new format used by other built-ins

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-18 12:28:40 +02:00
Joachim Nilsson d4fdf50636 Add optional support for RFC867, Daytime Protocol
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-18 12:06:59 +02:00
Joachim Nilsson 4f7366640b Add optional support for RFC864, Character Generator Protocol
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-18 11:48:04 +02:00
Joachim Nilsson 90497af7bb Add optional support for RFC863, Discard Protocol
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-18 09:55:19 +02:00
Joachim Nilsson cd0983a7f6 First draft of README refactor and split
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-15 15:52:19 +02:00
Joachim Nilsson c7573fedad Replace 'initctl emit <EV>' with 'initctl cond <cmd> <COND>'
This patch replaces the old 'initctl emit <EV>' idea with a more
full blown condition generator:

    initctl cond <set|clear|flux> <COND>

This aligns better with terminology used elsewhere in the new Finit
service state machine and dependency handling already documented.

The 'flux' sub-command is mostly intended for simulation/test of
Finit itself and should perhaps not be documented.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-15 15:51:57 +02:00
Joachim Nilsson 2b74fb0e93 Minor cleanup and corrections for new terminology
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-15 15:51:57 +02:00
Joachim Nilsson eb57457522 Document /etc/rc.local support
- Document /etc/rc.local support
- Update documentation around runparts(8)

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-15 13:53:10 +02:00
Joachim Nilsson f0cda83d24 Clean up AC_ARG_WITH and use config.h also for default paths
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-15 13:17:09 +02:00
Joachim Nilsson fbacae7071 Minor cleanup
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-15 13:17:09 +02:00
Joachim Nilsson 48e2cbd183 Add convenient SysV init /etc/rc.local compat
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-15 13:17:09 +02:00
Joachim Nilsson 8f9ea0ae57 Fix stupid spelling error
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-15 08:41:06 +02:00
Joachim Nilsson 1c0776b818 Tie in service and condition documents with README
This is a first effort at cleaning up and consolidating all information
about the new service state machine and how conditions control this
state machine.

Also, clarified and added sections for all documents regarding how
services and conditions relate.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-14 16:08:44 +02:00
Joachim Nilsson 6ff9cb2ff3 Rename condition net/gw --> net/route/default in netlink plugin
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-14 15:41:47 +02:00
Joachim Nilsson fbef03a4c6 Update Inetd features and service dependencies
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-14 10:03:19 +02:00
Joachim Nilsson 66f22a0a5f Add syntax highlighting helpers for Emacs
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-14 09:52:22 +02:00
Joachim Nilsson 171ae7dc85 Add support for disabling the Netlink plugin
Some vendors provide their own Netlink plugin to Finit.  This patch
makes it possible to disable the default netlink plugin from being
built.  However, even before this patch it was possible to overload
the plugin.  This just discards it from being built.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-13 13:23:07 +02:00
Joachim Nilsson ebfa8f061c Fix default handling in M4 macro AC_PLUGIN()
The AC_PLUGIN() could not properly handle if a plugin is to be enabled
by default.  This patch adds support for outputting the correct help
text.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-13 13:20:56 +02:00
Joachim Nilsson 2baa4f8ea9 Followup to 38203ab, remove queue.h from Makefile as well
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-13 13:07:28 +02:00
Joachim Nilsson 38203ab9e8 Migrate to libite version (newer) of BSD queue.h
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-12 15:34:52 +02:00
Joachim Nilsson 88a4ebf9e7 Use <> instead of "" for external header includes
Libraries and system headers should be included with <> instead of "".
This makes a great difference for the automatic dependency tracking.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-12 15:32:36 +02:00
Joachim Nilsson 51f61939da Do not build insecure inetd time (rdate) plugin by default
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-12 13:36:47 +02:00
Joachim Nilsson 7262a25c85 Merge pull request #34 from troglobit/echo
Basic inetd echo server support and bugfix

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-12 12:38:14 +02:00
Joachim Nilsson 8b9309ee41 Fix regression in starting internal inetd services
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-12 12:24:28 +02:00
Joachim Nilsson affc6a97b9 Add support for inetd RFC862 echo server
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-12 09:58:25 +02:00
Joachim Nilsson ec041b3c02 Update configure and build section
Prune standard configure flags and focus on the most important, whatever
they may be.  Mention --disable-inetd and describe how --enable-static
works.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-09 12:38:45 +02:00
Joachim Nilsson 267eeb9692 Fix --enable-static build, only C library shared
This patch fixes regressions in --enable-static introduced with the
conversion to the GNU configure and build system.

The default link flag to libtool is set to -static-libtool-libs, meaning
not a fully static build -- the C library will still be used as an .so
which is usually what people want -- whereas libite (-lite) and libuEv
are linked statically.

$ ldd /sbin/finit /sbin/initctl
/sbin/finit:
	linux-vdso.so.1 =>  (0x00007ffffde62000)
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f6979ad8000)
	/lib64/ld-linux-x86-64.so.2 (0x000055d893e96000)
/sbin/initctl:
	linux-vdso.so.1 =>  (0x00007ffed0dd6000)
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007feb3a29c000)
	/lib64/ld-linux-x86-64.so.2 (0x00005556ebd2b000)

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-09 12:14:21 +02:00
Joachim Nilsson 58e00fe52e Fix #17: Mention kernel CONFIG_UEVENT_HELPER_PATH and /etc/fstab
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-09 11:15:33 +02:00
Joachim Nilsson a40301ef86 Bring Building section more up to date
Now that we have a proper GNU configure script there is no such thing as
lightweight, and the respected environment variables are listed at the
end of `./configure --help`

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-09 11:14:03 +02:00
Joachim Nilsson 3a86db7d9f Fix typo in --enable-rw-rootfs configure option
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-09 10:30:31 +02:00
Joachim Nilsson 927956bf78 Set correct initial bootstrap runlevel 'S'
This patch corrects a long standing issue with Finit.  System initial
bootstrap runlevel must be set to 'S' (0), not the configured fallback
runlevel 'RUNLEVEL', which likely is '2'.

Also, minor cleanup, reduce code duplication.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-09 10:24:15 +02:00
Joachim Nilsson 05938a88ce Fix #33: Set up directory required by D-Bus plugin
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-09 10:04:34 +02:00
Joachim Nilsson 4a8a92af2e Minor audit of new top-level state machine
Also, give Jonas copyright for his contribution to Finit.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-06-07 18:32:31 +02:00
Joachim Nilsson 79b95daf3a The pidfile plugin requires /var/run, so depend on bootmisc
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-06-06 19:44:21 +02:00
Joachim Nilsson ea21bfc4c9 Relocate global sm variable to reduce include file deps
The new state machine handling is not necessary to export to external
plugins, so this patch reduces the exposure of the global variable sm

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-06-04 23:10:47 +02:00
Joachim Nilsson e9da876a10 Actually fix fallback shell memory leak
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-06-04 22:08:12 +02:00
Joachim Nilsson ef7f0b100b Check return value from fcntl() on inetd server socket
Setting O_NONBLOCK on an inetd server socket may fail, we
must check for this or the event loop may stall and block
Finit completely.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-06-04 21:53:42 +02:00
Joachim Nilsson 33ccff7733 Audit ad2bafb: cleanup of stale pid files
Make sure to check return value of remove(), it may actually signal
something useful.  Log useful errors.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-06-04 21:46:25 +02:00
Joachim Nilsson 00e5a8f5d9 Audit ec25051: service logging support
- Must check return value from open(), found by Coverity Scan
- Minor refactor (and cleanup) to reduce code complexity

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-06-04 21:38:46 +02:00
Joachim Nilsson f74a73be20 Audit commit 1177c73: musl libc compat changes
Must initialize init_request buffer to zero before communicating with
Finit.  Found by Coverity Scan.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-06-04 21:21:24 +02:00
Joachim Nilsson 34d8848b5c Fix leak if fallback shell cannot be registered
If we cannot register a fallback TTY we leak a few bytes RAM.
Found by Coverity Scan.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-06-04 21:15:16 +02:00
Joachim Nilsson 662f364d09 Check return value from uev_io_init() at runtime
Possible resource leak due to unchecked return value from uev_io_init()
found by Coverity Scan.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-06-04 21:03:36 +02:00
Joachim Nilsson e53acd1cdd Fix minor type warning in debug message
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-06-04 20:14:43 +02:00
Joachim Nilsson d96d1a3023 Audit rlimit support, handle possible NULL pointer
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-06-04 20:10:37 +02:00
Joachim Nilsson f249210c04 Update Travis-CI build script for Coverity Scan
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-06-04 19:52:33 +02:00
Joachim Nilsson 969ecffc05 Merge branch 'westermo-finit-sm'
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-06-04 19:49:33 +02:00
Joachim Nilsson cc15d3f77b Merge branch 'finit-sm' of https://github.com/westermo/finit into westermo-finit-sm
Hand merged conflicts in the following files:
	Makefile
	finit.h
	service.c

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-06-04 19:48:08 +02:00
Jonas Johansson ad2bafbfe8 services: remove .pid file for (careless) died processes
Signed-off-by: Jonas Johansson <jonas.johansson@westermo.se>
2016-05-20 09:08:38 +02:00
Jonas Johansson c5fad8e659 services: do not start services before all stopped processes has been halted
Signed-off-by: Jonas Johansson <jonas.johansson@westermo.se>
2016-05-19 14:46:59 +02:00
Jonas Johansson c1f725340d plugin/pidfile: also notify on modified pidfiles
Signed-off-by: Jonas Johansson <jonas.johansson@westermo.se>
2016-05-19 13:39:56 +02:00
Jonas Johansson 29315090f9 sm: handle reload event
Signed-off-by: Jonas Johansson <jonas.johansson@westermo.se>
2016-05-18 10:40:01 +02:00
Jonas Johansson 60df2043ac sm: handle runlevel change
Signed-off-by: Jonas Johansson <jonas.johansson@westermo.se>
2016-05-18 10:18:40 +02:00
Joachim Nilsson d48da81026 Merge pull request #31 from thezbyg/master
Fix SIGSEGV due to writes to const char array.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-05-17 20:28:35 +02:00
Albertas Vyšniauskas 5b86c76694 Fix SIGSEGV due to writes to const char array.
If no console is configured, then the following code gets executed:
int conf_parse_config(void)
{
  ...
  char *fallback = FALLBACK_SHELL;
  ...
  tty_register(fallback);
  ...
}
int tty_register(char *line)
{
  ...
  cmd = strtok(line, " ");
  ...
}
FALLBACK_SHELL is constant character array and strtok tries to modify
the first argument, which causes a crash.
2016-05-17 20:38:42 +03:00
Jonas Johansson 364f3bbafb finit: add finit state machine
Signed-off-by: Jonas Johansson <jonas.johansson@westermo.se>
2016-05-16 15:17:02 +02:00
Joachim Nilsson 9a539c636a Merge pull request #30 from westermo/wmo/2.4
Resource limit manipulation (setrlimit)

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-05-01 11:14:08 +02:00
Joachim Nilsson ca830b9a09 Compat install-dev hook
Finit <3 did not use GNU configure and build system.  This patch adds an
install-dev rule that is used by some to install required headers for
external plugin developers.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-30 16:53:43 +02:00
Joachim Nilsson f2b0951d78 Install headers for external plugin devs
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-30 16:39:51 +02:00
Tobias Waldekranz 6d84fd010e Resource limit manipulation (setrlimit)
Add support for changing the initial hard and soft resource limits for
finit and any processes it launches.

See /etc/finit.conf section in README.md for more information.
2016-04-28 09:36:22 +02:00
Joachim Nilsson 110ee220e7 Merge pull request #29 from westermo/wmo/2.4
Allow debugging of inetd service's arguments
2016-04-26 11:04:47 +02:00
Joachim Nilsson f29dff691f Allow debugging of inetd service's arguments
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-26 11:02:32 +02:00
Joachim Nilsson a1e6febc4f Merge pull request #28 from westermo/wmo/2.4
Westermo fixes for services changing type at runtime

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-26 09:38:41 +02:00
Joachim Nilsson df1fbbc996 Handle type change from inetd to service
When a service changes type from inetd to a regular daemon we must make
sure to first deregister the currently running inetd service properly.

Example: a system boots up with httpd.conf as an inetd service, so Finit
   opens a socket 0.0.0.0:80 pending connections to start `httpd -i`.
   After a while a user changes httpd.conf to be a regular service and
   calls `initctl reload`.  Without this patch the socket will remain
   open and prevent httpd from opening and binding to the same port.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-26 09:30:00 +02:00
Joachim Nilsson 448a9e1198 Stop inetd watcher and close socket when inetd service is removed
This patch fixes a problem with lingering inet sockets when inetd
services are removed.  When removing an inetd service we must stop
the watcher and close the socket.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-26 09:27:30 +02:00
Joachim Nilsson 80624d3ff8 Revert "Do not just mark deleted SVC free, clear memory"
We cannot clear the svc_t memory because other applications may have
connected to the same shared memory.  An application may be inspecting
the current list of services (initctl) and pulling the rug from under
them could cause some really unpredicatble results.

This reverts commit 06d1e90bac.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-26 09:23:59 +02:00
Joachim Nilsson 4b0f78c1b5 Merge pull request #27 from westermo/wmo/2.4
Westermo fixes for UDP inetd services and more

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-24 12:06:43 +02:00
Joachim Nilsson 5ea3cc0090 Reduce max backlog in listen(): 20 --> 10
Both the original MIT Athena inetd and the GNU inetutils inetd only keep
a backlog of 10 connections in listen() for TCP sockets.  This patch
adjusts the Finit hard coded default accordingly.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-24 12:01:10 +02:00
Joachim Nilsson 7f5f8ba09d Minor grammar: "Connection" --> "connection"
When starting an inetd service in verbose mode we print a progress
message to the console appended with "Connection".  This patch simply
changes that to append with "connection" in lower case.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-24 12:01:10 +02:00
Joachim Nilsson efd265c9c8 Fix "broken pipe" problem for UDP inetd services
This patch fixes several issues related to the problem of launching
UDP inetd services:

- Make sure to disable O_NONBLOCK on the socket before passing it to
  the inetd service, that's what is expected.  This goes for both UDP
  and TCP (accepted) connections -- there is no guarantee even for TCP
  sockets that they do *not* inherit the parent socket's flags.
- Mark the UDP inetd parent's SVC as busy and stop its watcher before
  starting the child task to service the connection.  The watcher must
  be stopped or multiple child tasks may be spawned!
- Only copy the most relevant parts to the UDP task.  In particular
  must *not* copy the libuEv watcher data to the task!
- With the child task done and the parent inetd service unblocked we
  must restore O_NONBLOCK to the socket before restarting the watcher

When a UDP inetd service connection is handled we create a child task
to service the request, meanwhile we block the parent service.  There
was a problem with blocking the parent since we called inetd_stop(),
which both did a shutdown() and close() of the socket ... this patch
introduces separate handling of blocked (busy) inetd services in the
inetd_stop() function and also make sure to handle restarting the
parent watcher in inetd_start() when the child task is done.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-24 12:01:10 +02:00
Joachim Nilsson 7e91cb4afc Minor log message improvements
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-24 12:01:10 +02:00
Joachim Nilsson 9a03adce5a Do not assume new fd is 0, dup2() with fd instead
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-24 10:54:31 +02:00
Joachim Nilsson 06d1e90bac Do not just mark deleted SVC free, clear memory
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-24 10:53:20 +02:00
Joachim Nilsson 439d9df122 Set CLOEXEC flag to prevent leaking descriptors
Both the new initctl API and the new pidfile watcher plugin failed to
set CLOEXEC on their sockets.  This caused forked-off and exec()'d
children to inherit all these descriptors.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-24 10:52:39 +02:00
Joachim Nilsson f44ac5a023 Remove bogus autoconf version requirement
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-17 00:20:26 +02:00
Joachim Nilsson 84c75c4416 Rename internal pkg-config reference to libuEv
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-17 00:18:11 +02:00
Joachim Nilsson ee8a69f5ed Let plugins know search path for lite.h
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-16 22:05:31 +02:00
Joachim Nilsson acf6cb6900 Show configure log to see where hell breaks loose
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-16 21:58:53 +02:00
Joachim Nilsson f51183d5f2 Strip install libs, do not use DESTDIR for Finit
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-16 21:55:39 +02:00
Joachim Nilsson ff5814e4d4 Use pkg-config provided paths for uEv and lite
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-16 21:45:21 +02:00
Joachim Nilsson 831d0c5520 Use /tmp as install --prefix for libs, not DESTDIR
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-16 21:21:48 +02:00
Joachim Nilsson d9cc21b3c8 Travis-CI: Attempt to build w/o root privs
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-16 21:12:45 +02:00
Joachim Nilsson 096a3eff51 Mention new log keyword to services et al
Patrick Stewart added the optional `log` keyword to service, run, task
and inetd stanzas in 889bce1.  It redirects stdout/stderr to syslog
using the logger tool.  This addition to the README is mainly just a
place holder so it's not forgotten before the upcoming README refactor.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-13 23:56:02 +02:00
Joachim Nilsson 889bce1768 Merge pull request #26 from RFCreations/master
Some fixes, and add logging

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-13 23:46:01 +02:00
Patrick Stewart 0ba8df5c2d Change stdin member of svc to stdin_fd
'stdin' is a macro in stdio.h, so it shouldn't be used as a member name. GLIBC happens to have "#define stdin stdin", but other libcs don't.
2016-04-13 22:09:05 +01:00
Patrick Stewart ec2505191b Add service logging
Adds an extra 'log' parameter to services that routes STDOUT and STDERR to syslog.
Uses a PTY rather than a pipe, as this prevents log messages hanging around in a buffer indefinitely.
2016-04-13 22:09:05 +01:00
Patrick Stewart 3de9e4e5db Fix potential race condition/hang for SVC_TYPE_RUN services
In service_start() the SIGCHLD handler is reenabled before calling complete(), so the service could be reaped by the SIGCHLD handler leaving service_start() waiting forever
Also remove code that duplicates sig_unblock()
2016-04-13 22:09:05 +01:00
Patrick Stewart 1177c734ce Use finit API to get runlevel instead of utmp
utmp is not available with musl libc
2016-04-13 22:07:39 +01:00
Joachim Nilsson f7f222c924 Minor formatting and sectioning
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-13 07:45:28 +02:00
Joachim Nilsson dd8715f3dc configure.ac: Cleanup, remove commented out old ideas
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-13 07:43:40 +02:00
Joachim Nilsson 3e93ed2ead TODO: Add support for throttling connections
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-13 07:40:57 +02:00
Joachim Nilsson e50e12417e README.md: Attempt to update to new build system
First attempt to update and simplify the build instructions and example.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-13 07:37:34 +02:00
Joachim Nilsson 9e70a12273 configure.ac: Remove datarootdir
Unused after removal of GIT submodules.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-13 07:36:41 +02:00
Joachim Nilsson b313e623df Remove double slash '//bin' from default prefix path
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-13 07:22:27 +02:00
Joachim Nilsson 376d7a0fbb m4/plugin.m4: Minor cleanup
Use pure M4 syntax, not mixed with -P syntax.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-13 07:17:02 +02:00
Joachim Nilsson 1398536194 README.md: Update initctl help text
Add missing `initctl cond show` help.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-12 23:48:28 +02:00
Joachim Nilsson 95135ca0a7 README.md: Slightly friendlier warning
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-12 23:42:25 +02:00
Joachim Nilsson ec31930638 README.md: Mark optional plugins as optional
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-12 23:39:00 +02:00
Joachim Nilsson ed8b21db36 plugins/Makfile.am: Make optional plugins optional
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-12 23:36:35 +02:00
Joachim Nilsson b1cd3a2332 Make a few less used plugins optional
The alsa-utils, dbus, lost (PID), resolvconf, and x11-common plugins are
rarely used in the main use-case for Finit (embedded head-less systems).
This patch disables them by default and makes them possible to enable by
configure --enable-$PLUGIN switches.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-12 23:34:27 +02:00
Joachim Nilsson 5675d068f8 m4/plugin.m4: Simplify, fix and cleanup M4 code
Slightly more readable code and fix issue with --enable-$PLUGIN not
biting properly in the generated Makefile.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-12 23:32:52 +02:00
Joachim Nilsson 4baf2611f6 Foundation for selecting plugins in configure
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-12 20:30:29 +02:00
Joachim Nilsson 13d4821abe Disable fast-install by default
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-11 07:29:01 +02:00
Joachim Nilsson 1f1c2e0466 Replace verbose and kernel quiet modes with silent and quiet
This patch replaces the verbose and kernel-quiet runtime options with
a (hopefully) more useful quiet and silent modes of operation.

By default Finit progressively shows all services it starts at boot, but
when boot has completed and services are started/restarted Finit prints
nothing.  If `--disable-quiet` is given all started/restared/stoppping
messages are shown even after boot.

However, if `--enable-silent` is given Finit is completely silent even
at boot, no progress is shown, until the first service is started, which
on most systems is login.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-11 00:50:37 +02:00
Joachim Nilsson c4af8b7cbd configure: Shorten and clarify descriptions
This patch makes a few configure options shorter, but still more clear.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-11 00:49:24 +02:00
Joachim Nilsson 426d915c08 configure: Remove --with-aix-soname=aix|svr4|both
Remove confusing `--with-aix-soname` option to configure.  Replace with
hard-coded `aix-soname=both` => shared + static archives are build as to
be expected.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-11 00:46:31 +02:00
Joachim Nilsson 86be6812b9 configure: Remove GIT submodule check
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-11 00:45:37 +02:00
Joachim Nilsson 4efdc4fe19 Merge pull request #25 from westermo/wmo/2.4
Westermo fixes to Finit3
2016-04-10 20:08:25 +02:00
Joachim Nilsson da76cf4f75 Check return value from strtok(), may be NULL
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-10 19:58:46 +02:00
Joachim Nilsson a2177a8063 Fix GCC warning for signed vs unsigned comparison
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-10 19:58:13 +02:00
Joachim Nilsson cfa155deae Minor cleanup
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-10 19:57:48 +02:00
Joachim Nilsson e7832e2ca7 FTBFS followup issue #24
Add missing return keyword to inline function svc_is_starting()

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-10 19:56:13 +02:00
Joachim Nilsson d7d45b65d0 Merge pull request #24 from westermo/wmo/2.4
Assert svc condition only when PID file has been created/updated

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-10 19:50:16 +02:00
Joachim Nilsson 4ae5c54f45 Assert svc condition only when PID file has been created/updated
This patch prevents too early start of services depending on other
services.  E.g, if service B depends on A then we must wait for A to
signal that it is ready before we allow B to start -- in a Finit based
system A does this by creating, or touching (updating mtime), its PID
file.  Services (like A) that support SIGHUP should call utime(), or
utimensat(), on the PID file at the end of their SIGHUP handler.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-10 19:14:48 +02:00
Joachim Nilsson 7b8944730d README: This is Finit3, development version
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-09 20:42:44 +02:00
Joachim Nilsson 87ca6574b8 Travis-CI: Build & install libuEv and libite first
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-09 20:37:09 +02:00
Joachim Nilsson 35844f2d1d Update finit_LDADD for external libuEv and libite
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-09 20:35:38 +02:00
Joachim Nilsson 2e2d87ee78 Update include path for libuEv and libite
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-09 20:33:07 +02:00
Joachim Nilsson ba11d218bc Remove local GIT submodules for libuEv and libite
From now on the user is required to have libuEv and libite installed
before building and installing finit. This is for maintenance reasons.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-09 20:29:26 +02:00
Joachim Nilsson 707c42db63 Update TODO, remember our origins!
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-05 20:18:31 +02:00
Joachim Nilsson 4cfe4781a3 Remove old (now unused) compat symlinks
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-05 20:17:38 +02:00
Joachim Nilsson 8f415aeaf6 Add HOOK_SVC_START to detect started processes
This patch adds support for the runtime `HOOK_SVC_START`.

Customer request.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-05 03:45:23 +02:00
Joachim Nilsson 3f3220e806 Add HOOK_SVC_LOST to detect lost processes
This patch adds support for the runtime `HOOK_SVC_LOST` and the (very
noisy) *example* plugin `lost.so`.

Customer request.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-05 03:33:58 +02:00
Joachim Nilsson e54c7eef65 Fix dlopening of plugins
Finit must export symbols, but plugins do not since they are modules.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-05 03:20:10 +02:00
Joachim Nilsson 05cc6bf5d2 Do not bail on makepath() fail if dir exists
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-05 03:16:40 +02:00
Joachim Nilsson 4fecb8621d Fix PLUGIN_PATH => $(pkglibdir) in build system
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-05 02:38:24 +02:00
Joachim Nilsson 6a49f7ed8c Add missing license, copyright and module description
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-03-21 15:56:15 +01:00
Joachim Nilsson 8bcc34ce91 Remove Emacs version-control handling
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-03-21 15:41:51 +01:00
Joachim Nilsson 8da1505454 Minor, use () to denote function in comments
To distinguish between variables and functions in comments Finit use ()
at the end of function names.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-03-21 15:14:12 +01:00
Joachim Nilsson 34e4d31219 Travis-CI: Set LD_LIBRARY_PATH to /tmp/lib for initctl -h
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-03-19 23:03:41 +01:00
Joachim Nilsson 6489dcc967 Update .gitignore files
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-03-19 23:00:00 +01:00
Joachim Nilsson 2d6769005a TODO: Add Westermo request for initctl show --json
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-03-19 22:56:05 +01:00
Joachim Nilsson 98cd6dffb1 Fix build and install temporarily
This patch builds Finit dynamically, including both plugins and GIT
submodules for libite and libuev.  This causes libite.so and libuev.so
to be installed in a public path, which is not good if the user has
other versions of the same libraries already installed.

The correct fix is to remove the GIT submodules for now and require
users of Finit to build and install libite and libuev separately.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-03-19 22:54:07 +01:00
Joachim Nilsson eb86a76a0d Travis-CI: Remove extra call to configure
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-03-19 22:51:34 +01:00
Joachim Nilsson 4423a2b16e Fix Travis-CI build, move package install
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-03-18 21:32:23 +01:00
Joachim Nilsson 0467c571df Merge pull request #22 from westermo/wmo/2.4
initctl: Only show service name, not path, with plain show
2016-03-17 22:04:27 +01:00
Joachim Nilsson cef4b5761a initctl: Only show service name, not path, with plain show
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-03-16 13:06:47 +01:00
Joachim Nilsson 806d05622a Fix libite.la library dependency in build
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-03-15 08:20:48 +01:00
Joachim Nilsson 57fb4738f1 Create empty m4 directory for the benefit of autogen.sh and Travis-CI
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-03-15 07:34:20 +01:00
Joachim Nilsson 0bbc69200b Update Travis-CI to use ./autogen.sh before configure & build
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-03-15 00:13:07 +01:00
Joachim Nilsson 726f0d428d Initial conversion to GNU Configure & Build System
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-03-14 22:35:54 +01:00
Joachim Nilsson 0704947c33 Merge pull request #20 from westermo/wmo/2.4
inetd reload fixes

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-02-19 15:11:20 +01:00
Tobias Waldekranz 2555fe8e96 inetd: Flush existing filters on reload
Flush any existing filter rules when a configuration file is
updated. Otherwise filters are simply appended to the old
configuration which can cause finit to accept connections on
interfaces that are blocked in the new configuration.
2016-02-19 12:53:39 +01:00
Tobias Waldekranz c41016ef32 Only default to SIGHUP support on daemons
When parsing a service configuration, only default to SIGHUP support
if the service is a daemon. inetd services must be stop/started on
change.
2016-02-19 12:50:24 +01:00
Joachim Nilsson 5d86137142 Fix Coverity warning for unchecked return value from mkdir()
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-02-05 23:13:47 +01:00
Joachim Nilsson bd58345b8c Fix Coverity warning for unterminated string from read()
The read() does not zero terminate the string, then we call strstr() on
that string ...

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-02-05 23:01:24 +01:00
Joachim Nilsson 994b589377 Fix Coverity warning for possible NULL ptr dereference
Add check for return value from strtok()

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-02-05 22:55:39 +01:00
Joachim Nilsson caff08f58d Fix Coverity warning for unchecked return value from dirname()
- Check return value from dirname()
- Remove static from local compose buffer

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-02-05 22:50:08 +01:00
Joachim Nilsson d58c58d972 Test build with both GCC and Clang (LLVM)
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-02-05 21:57:58 +01:00
Joachim Nilsson a97499999e Remove initial make distclean step, not needed
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-02-05 21:54:34 +01:00
Joachim Nilsson 9c7046a25d Fix linking error with new autotools based libraries
We may have reached peak Makefile mastery now ...

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-02-05 21:44:21 +01:00
Joachim Nilsson cd5d55ef51 Call libuev configure script if local libuev is used
Same as for libite, libuev has also changed to autotools, so
call its autogen.sh and configure script in cascade from our
own.  Aslo add safeguards to clean/distclean targets so we
do not attempt to enter the libuev subdirectory if it's not
configured.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-02-05 21:43:04 +01:00
Joachim Nilsson 5eb172ed46 Update to libuEv v1.3.1
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-02-05 21:23:16 +01:00
Joachim Nilsson 3d99940252 Bump version to 3.0-beta1
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-02-05 21:10:47 +01:00
Joachim Nilsson fce420121c Fix unused variable warning
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-02-05 21:10:25 +01:00
Joachim Nilsson 6c91c4ec12 Fix unused variable warning
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-02-05 21:09:31 +01:00
Joachim Nilsson 2cb5997abe Fix signed/unsigned comparison warning
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-02-05 21:09:20 +01:00
Joachim Nilsson 5afb47bc9b ChangeLog: Add missing links to referenced previous versions
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-02-05 21:08:21 +01:00
Joachim Nilsson d6d92f1df7 Increase indentation in pretty printing slightly for autotools
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-02-05 21:07:17 +01:00
Joachim Nilsson 4899bba06b Call libite configure script if local libite is used
The new libite uses autotools to build, and since we use it as a GIT
submodule we have to call its autogen.sh before we call the configure
script, from within the Finit configure script.  We may have to move
to use autotools even for Finit ...

Also, make sure to only call clean/distclean on libite if the local
version is selected at configure time.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-02-05 21:06:46 +01:00
Joachim Nilsson 97a160dd1d Update to libite v1.4.3
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-02-05 20:26:40 +01:00
Joachim Nilsson 901bdc68ba Merge pull request #19 from westermo/wmo/2.4
Service state machine and refactored event/condition handling

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-02-05 16:44:51 +01:00
Tobias Waldekranz c6055031b8 Avoid unnecessary restarts of services that do not support SIGHUP
When a service's condition transitions to `flux`, put it in the
waiting state, even if it does not support SIGHUP. That way, if the
condition returns to `on` we can simply SIGCONT it. If it goes to
`off` it will still be stop/started as before.
2016-02-05 13:45:06 +01:00
Tobias Waldekranz e8d699c194 Mark inetd services as clean on dynamic reload
When reloading dynamic services, inetd services deleted marker was not
being cleaned. This caused finit to stop and start all inetd services
at every other reload.
2016-01-28 14:52:49 +01:00
Tobias Waldekranz 80273555c5 Do all service transitions in a helper function
This eases development, since it makes it easy to set a breakpoint on
a specific state transition.
2016-01-28 13:44:27 +01:00
Tobias Waldekranz 6ece4b8fa3 inetd: Re-integrate the inetd subsystem into the new service model
This patch introduces a new service type called SVC_TYPE_INETD_CONN,
which represents a running inetd connection. These are handled in much
the same way as tasks. I.e. they are considered one-time jobs, with
the difference that they are removed upon completion.
2016-01-15 10:07:15 +01:00
Tobias Waldekranz 0beb566e45 git: Ignore Emacs backup files 2016-01-13 16:02:46 +01:00
Tobias Waldekranz c641a1374e Do not ignore updated services when cleaning up removed ones
When cleaning up removed services, the assumption was made that if a
service was not 'removed', it was 'clean'. In reality, it could also
be 'updated', which was then overwritten, causing services not being
restarted. Don't do that.

As a future precaution, make the dirty field const, only allowing
updates from accessor methods.
2016-01-13 15:14:27 +01:00
Tobias Waldekranz 171d611b14 Improve service state machine debug messages
In addition to logging state transitions, also log the parameters that
might trigger a transition.
2016-01-13 15:09:04 +01:00
Tobias Waldekranz 02eb68f46c Ensure that a service has stopped before taking any further action
During documentation of the state machine, some theoretical problems
where discovered that could have lead finit to spawn a new instance of
a daemon before the previous one had been collected.

Now a service will always go through the STOPPING state when leaving
RUNNING. This ensures that the PID has been collected before any calls
to service_start.

...documenting your work is, apparently, not a bad idea. :)
2016-01-07 11:00:52 +01:00
Tobias Waldekranz 7fe4c3355f doc: Add service state machine documentation 2016-01-07 11:00:51 +01:00
Joachim Nilsson 5b28fed321 Audit.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-01-05 21:11:27 +01:00
Tobias Waldekranz aa1da0e9f2 doc: Add documentation for conditions 2016-01-05 17:24:31 +01:00
Tobias Waldekranz 2232aea0f7 Dynamically manage service states based on user defined conditions
Old event system has been replaced with a more generic condition
concept. The idea is that finit plugins may provide arbitrary
conditions that services may specify as dependencies that they require
to run.

In order to accomodate this, the service management has been
redesigned to use a state machine.
2016-01-05 15:01:58 +01:00
Tobias Waldekranz 7a3408c173 Optionally skip stripping binaries during install-exec
One may wish to build and install with debug symbols intact, so allow
overriding the arguments sent to install.
2016-01-05 14:50:13 +01:00
Tobias Waldekranz af7b6c17cb Correctly parse service configuration stanzas containing slashes
Parser would erroneously interpret an event specification containing
slashes as an inet service/proto specification.

E.g. "<net/gw>" was interpreted as port "<net" using protocol "gw>".
2016-01-05 14:50:13 +01:00
Joachim Nilsson a822a7657c Update ChangeLog and bump version for v2.4 release
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-12-04 19:15:48 +01:00
Joachim Nilsson e46271c1a9 Revert change in v2.3 listing stopped services as "paused"
Stopped services are now (again) listed as "stopped" and halted
services, due to a runlevel change, are listed as "halted". Several
users complained that this change was just not intuitive. I agreee.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-12-04 19:05:35 +01:00
Joachim Nilsson 1028725079 Add support for 'initctl show dropbear:2'
By popular request, this patch adds support for querying status of a
single service.  The syntax is similar to that of stop/start/reload.

Both `initctl show ...` and `initctl status ...` is supported.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-12-03 20:05:25 +01:00
Joachim Nilsson ed5ee667ae [Patch 2/2]: Make sure to start/SIGHUP services when none were stopped
When no services were stopped we must ensure to start/SIGHUP any new or
SIGHUP:able services as the last pass of the `initctl reload` cycle.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-12-02 13:06:16 +01:00
Joachim Nilsson 4c3e053041 [Patch 1/2]: System reconfiguration causing system freeze
This patch fixes a hang when performing a system reconfiguration using
`initctl reload`, `SIGHUP` or running `(f)init q`, which caused Finit
to wait for SIGHUP:able services to stop.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-12-02 13:02:40 +01:00
Joachim Nilsson a5c5a5c644 Allow debug mode to override terse mode
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-12-01 22:36:16 +01:00
Joachim Nilsson fa3a97366c Update Debugging section, all interesting stuff is in configure now
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-12-01 22:30:08 +01:00
Joachim Nilsson 5b3e3da7ff Attempt to clarify how BusyBox getty works wrt. the TTY device path
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-12-01 22:24:21 +01:00
Joachim Nilsson 59d96f264d Reenable verbose mode at reboot, if disabled at boot
This patch reenables verbose mode at shutdown/reboot, if it was disabled
at boot.  This allows the user to see the output from the `urandom.so`
and `hwclock.so` plugins at reboot.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-11-30 22:31:48 +01:00
Joachim Nilsson 7027cbc439 Enforce terse mode after boot, if verbose is disabled
The urandom.so plugin uncovered that `print_desc()` does not honor the
`verbose` flag.  At runtime `print_desc()` et al should no be displaying
anyting when we finit operates in terse mode.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-11-30 19:45:27 +01:00
Joachim Nilsson 8218fff7e5 Update ChangeLog and bump version for v2.3 release
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-11-28 13:59:47 +01:00
Joachim Nilsson 263e23a0df initctl: Support for stop/start services by name:id
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-11-26 21:22:05 +01:00
Joachim Nilsson 1f88e1ff8a Refactor svc_status() used by 'initctl show'
Leverage new svc_t states in initctl status/show output.  Also, ensure
different svc_t types have correct start state.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-11-26 20:51:04 +01:00
Joachim Nilsson b4ccc8b008 Clean up bootstrap-only tasks when leaving bootstrap 'S' runlevel
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-11-26 20:22:24 +01:00
Joachim Nilsson 8df2b7b6e9 service_stop_dynamic(): Skip already stopped and HALT removed services
new postponed stop handling tried to reload already stopped and removed
services.  We should of course skip already stopped services and halt
those that have been removed.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-11-26 19:13:39 +01:00
Joachim Nilsson 8073f7cf27 Revert semantic change in 'initctl restart' introduced in 924bf04
This patch reverts the change in behavior introduced in Finit v2.2,
commit 924bf041, where `initctl restart JOB` changed from 'stop + start'
to `SIGHUP` for services that support `SIGHUP`.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-11-25 10:14:18 +01:00
Joachim Nilsson e303e1f833 Fix column alignment in initctl show for services not in current runlevel
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-11-25 09:36:56 +01:00
Joachim Nilsson 3ea4be9343 Fix NULL ptr dereference causing kernel panic
When `service_stop_done()` is called with a `NULL` argument and no
dynamic services have been stopped, this regression is triggered.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-11-25 09:30:53 +01:00
Joachim Nilsson d8188428ed Bump version for v2.2 release.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-11-23 13:20:44 +01:00
Joachim Nilsson d9f1882204 Update ChangeLog and prepare for release of v2.2
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-11-23 00:59:04 +01:00
Joachim Nilsson 4d899851cc Upgrade libite (LITE) to v1.2.0
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-11-23 00:45:55 +01:00
Joachim Nilsson ad8feca3e7 Upgrade libuEv to v1.2.4
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-11-23 00:45:20 +01:00
Joachim Nilsson 7569c479b8 Improve event debugging
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-11-22 22:18:56 +01:00
Joachim Nilsson e7db6c6ac6 Update README with latest changes to initctl help
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-11-22 22:18:40 +01:00
Joachim Nilsson f12535dc19 Clarify that the GW event to listen for in service declarations is GW:UP
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-11-22 22:18:15 +01:00
Tobias Waldekranz b19ea16e9d Only trigger on events that matches the service's specification
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
2015-11-22 19:59:01 +01:00
Joachim Nilsson eb59155dad Enable mdev logging when Finit runs in debug mode
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-11-22 19:53:44 +01:00
Joachim Nilsson f38dfaf2dc Pretty printing of current runlevel in initctl show
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-11-22 15:58:32 +01:00
Joachim Nilsson 4ada42f380 Add debug flag to initctl client tool
This patch makes it possible to see debug traces when running the client
program initctl, using `--debug`.  Please note, this does not affect the
debug command to the daemon.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-11-22 15:57:56 +01:00
Joachim Nilsson 924bf041bc On reload/restart we must wait for services to stop first
This patch adds support for declaring *why* a service is being stopped
or reloaded.  This is later used when all stopped services have been
collected by the `service_monitor()` to issue start or postponed SIGHUP.

As an added benefit we can now also see why a service is not running.
If it has been paused by a user, halted when moving to another runlevel,
waiting for a condition (event), or similar.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-11-22 10:11:27 +01:00
Joachim Nilsson b1d57d6828 Set default value for svc->sighup, even if service has no event mask
The `initctl reload <JOB>` command did not work properly.  This
was due to the service not being properly initialized to default
settings when reading the Finit configuration file.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-11-22 10:05:57 +01:00
Joachim Nilsson 87f9b94b42 Call HOOK_SVC_RECONF only when all processes have been stopped
This patch fixes a race condition when doing an ordered RELOAD and STOP
event sequence.  For services that shall be stopped it is imperative
that we wait for them to be colleced by the `service_monitor()`, so that
we know they have really been stopped, before calling HOOK_SVC_RECONF.

The latter is a promise to external services that all services have been
indeed stopped.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-11-19 19:29:16 +01:00
Joachim Nilsson c8f0b97d0f tty.c: Handle EINVAL and use recommended inotify event size.
The TTY plugin might fail in read() with EINVAL if the inotify event
buffer is too small.  Fix: set the receive event buffer to the size
recommended in inotify(7).  Also add a handler for EINVAL to close and
reinitialize the inotify descriptor so we do not accidentally overrun
the CPU with any unhandled errors.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-10-26 04:33:51 +01:00
Joachim Nilsson f902505b5d Declare name for all plugins, needed for static builds.
When building a static Finit the plugins do not get a unique name
automatically from the file.  This led to only the first plugin being
loaded, since its name was 'unknown' it was registered as such and all
other plugins conflicted, since 'unknown' was already ... known and
loaded.

This patch gives all plugins a default name, __FILE__, making it
possible to use all of them when building a static Finit.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-10-26 03:44:43 +01:00
Joachim Nilsson a6b78d57c0 Clarify why we must define the name for inetd plugins.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-10-26 03:39:05 +01:00
Joachim Nilsson a33478d563 Improve urandom plugin for embedded systems w/o random seed.
For embedded systems with no initial random seed, usually stored in
/var/lib/urandom/urandom-seed on desktops, servers and laptops, we now
provide an initial seed file using a built-in PRNG.

Also, let the configure script default to *enable* the random seeding
at boot, granted the urandom plugin is enabled.  We should encourage
users to properly seed their random, for security reasons.

Moreover, the plugin did not properly regenerate the random seed on
reboot, or shutdown, this patch also rectifies that problem.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-10-26 03:31:19 +01:00
Joachim Nilsson 369fcf2100 Issue #14: Improved support for static Finit builds
- Upgrade libite (LITE) for new UNIX file parser API to improve static
  builds of Finit.
- Re-enable bootmisc plugin for static builds by adding built-in support
  for reading GID from /etc/group.
- Allow inetd support for static builds by adding built-in support for
  reading service and protocol from /etc/services and /etc/protocols.
- Do not try to install/uninstall any plugins for static builds.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-10-26 00:56:50 +01:00
Joachim Nilsson b2c5e97417 Disable bootmisc plugin entirely if configure --enable-static
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-10-22 19:01:19 +02:00
Joachim Nilsson 8725200260 Build fixes for configure --disable-inetd
service.c:
	Don't declare find_inetd_svc() if inetd is disabled.
api.c:
	Disable inetd API
initctl.c:
	Disable presentation of inetd services

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-10-22 18:59:20 +02:00
Joachim Nilsson 58980c72fa Misc. fixes to silence warnings when building a static Finit.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-10-22 18:39:46 +02:00
Joachim Nilsson bcc70ec774 Update libite and libuev to handle static builds.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-10-22 18:38:47 +02:00
Joachim Nilsson 44579cc089 README: Clarify how arguments to ./configure --with-plugins= work
This should help clarify any misunderstandings detailed in issue #13.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-10-22 15:19:01 +02:00
Joachim Nilsson da361f460d Update ChangeLog slightly, off by one fix
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-10-16 20:56:56 +02:00
Joachim Nilsson bc2cb21005 Update version links.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-10-16 20:46:34 +02:00
Joachim Nilsson e1169628ce Update ChangeLog and bump version for v2.1 release
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-10-16 20:44:47 +02:00
Joachim Nilsson 48b420b757 Simplify execution and _exit() of service callback.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-10-16 19:45:09 +02:00
Joachim Nilsson 9796809907 Merge pull request #12 from westermo/wkz/sighup-fix
Unblock blocked signals after forking off a child
2015-10-16 18:42:47 +02:00
Tobias Waldekranz a3193b34a6 Unblock blocked signals after forking off a child
After forking off a new child, all signals that are blocked by finit
should be unblocked before exec-ing the final binary. Also, finit now
blocks SIGHUP, so add it to the set of signals that should be
unblocked.
2015-10-16 18:32:53 +02:00
Joachim Nilsson c0af01db6d Upgrade libite (LITE) to v1.1.1
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-10-10 17:36:24 +02:00
Joachim Nilsson 3c1c7df420 Default to -O2, not -Os, and use CPPFLAGS for includes, not CFLAGS.
We should not use -Os as default optimization, it is sometimes unstable
in cross compilers.  Instead, default to -O2, which is the more tried
and tested path.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-10-10 17:34:31 +02:00
Joachim Nilsson 258efd4101 Cleanup, minor bug fixes and silencing of netlink plugin.
Patch courtesy of Westermo.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-10-08 19:59:19 +02:00
Joachim Nilsson 5e33647f80 Fix too small MAX args in initctl and too few args in svc_t
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-10-07 21:03:35 +02:00
Joachim Nilsson d2f23e281f Allow Finit to set hostname at dynamic reload.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-10-06 19:35:02 +02:00
Joachim Nilsson b5e3e69553 Do not allow VERSION to be overloaded by build system.
When integrating finit as a component in another system, that build
system may set VERSION as an environment variable for that OS -- we do
not want that version to be set as the version of finit.

Also, bump version to 2.0.1-dev for upcoming patch release cycle.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-10-02 15:09:07 +02:00
Joachim Nilsson 8d85e59214 Optimization is a CFLAG, not a CPPFLAG
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-09-29 22:39:49 +02:00
Joachim Nilsson a1c8ada320 Play around a bit with project title heading.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-09-29 22:39:19 +02:00
Tobias Waldekranz ae15988eb8 Add hook point on fstab mount failure
Check return code from `mount -na`, if there where any errors give
plugins a chance to do something about it.

Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-09-29 22:38:06 +02:00
Joachim Nilsson 9491f18972 service_enabled(): Only check WCOREDUMP() from if WIFSIGNALED()
Patch courtesy of Westermo.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-09-28 19:17:30 +02:00
Joachim Nilsson 545f3105e2 Update ChangeLog and bump version for v2.0 release.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-09-20 12:27:41 +02:00
Joachim Nilsson eec166a9eb Add simple service script for SysV init compat.
This patch adds a simple `service <script> <stop|start|reload|restart>`
script for for SysV init compatibility.  Very common with users of the
Ubuntu upstart init as well.

Also, fixed `make uninstall` for plugins.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-09-19 22:04:26 +02:00
Joachim Nilsson 125fc661a3 Makefile: Allow clean and distclean targets when libite/libuev are disabled.
Even though libite and libuEv can be disabled, using the --with-libnnn
option to configure, we let make descend into those submodules for the
clean and distclean targets.  This way we can rely on make dev to work.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-09-18 09:14:49 +02:00
Joachim Nilsson 6531b2f20a Add --with-libuev=PATH to configure script to use external libuEv
This commit makes it possible to build Finit with an external libuEv.
Without this configure script option the libuev submodule is used.

With an external libuEv we make sure to set the SONAME to libuev.so.1
to prevent any future runtime ABI issues.

Fixes issue #4.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-09-17 12:59:20 +02:00
Joachim Nilsson 1f84edfb8c Add --with-libite=PATH to configure script to use external libite
This commit makes it possible to build Finit with an external libite.
Without this configure script option the libite submodule is used.

With an external libite we make sure to set the SONAME to libite.so.2
to prevent runtime ABI issues with older libite versions.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-09-17 11:59:46 +02:00
Joachim Nilsson c354d0e7e6 Upgrade libite to v1.1.0
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-09-17 11:19:19 +02:00
Joachim Nilsson 98eb7cfea1 Upgrade libuEv to v1.2.3
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-09-17 11:18:38 +02:00
Joachim Nilsson ec80ce1c9b Add distclean step after Coverity run.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-09-15 11:58:53 +02:00
Joachim Nilsson ef05983dc8 Fix Coverity CID #149216: Buffer not NUL terminated
We should of course always use `strlcpy()` instead of `strncpy()`.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-09-15 11:49:47 +02:00
Joachim Nilsson 1c04097dca Update ChangeLog with new features and some Markdown syntax fixes.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-09-15 09:32:12 +02:00
Joachim Nilsson 36aba8952f Bump version to v2.0-beta1 for upcoming release and rename CHANGELOG.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-09-15 09:25:05 +02:00
Joachim Nilsson 6e07dd8dec Add support for starting/stopping services on Netlink events
This commit adds support for event based services to Finit.  Along with
the previously added support for multiple instances of the same process,
the feature scope for Finit v2.0 has been reached!

As of now a service can be declared in /etc/finit.conf or /etc/finit.d/
like this:

    service :1 [2345] <!IFUP:eth0,GW> /sbin/dropbear -R -F -p 22 -- SSH daemon

Here the first instance `:1` of dropbear is declared to run in runlevels
2-5, but only if eth0 `IFUP:eth0` is up and a gateway `GW` is set.  When
the configuration changes, a new gateway is set, or somehow a new `IFUP`
event for eth0 is received, then dropbear is not SIGHUP'ed, but instead
stop-started `<!>`.  The latter trick applies to all services, even
those that do not define any events.

Currently inetd services are not supported for event based starting, but
it could easily be added.  Likely scenario is to deny incoming requests
on, e.g., eth0 if there is no gateway.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-09-15 09:13:33 +02:00
Joachim Nilsson ffa32c6674 README: Clearify how multiple events can be emitted by initctl.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-09-15 09:05:10 +02:00
Joachim Nilsson c30039facf Minor refactor and cleanup.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-09-14 01:23:17 +02:00
Joachim Nilsson b13c6421b3 First Netlink plugin prototype.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-09-11 13:10:20 +02:00
Joachim Nilsson fcaf5d7b76 README.md: Commit to spec for v2.0 release.
The event API, including Netlink events to services, looks OK now
to build the remaining two features on:

- Netlink plugin for GW and IFUP IFDN events
- Generic event support for services

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-09-11 09:51:10 +02:00
Joachim Nilsson f9ddb1bdfc Make sure to always run HOOK_SVC_RECONF when services have been stopped.
Previously `HOOK_SVC_RECONF` was only called on `initctl reload`,
now we also call it on `initctl emit "STOP"`.  This seems like a
good idea atm, hopefully it will remain a good idea.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-09-11 08:58:39 +02:00
Joachim Nilsson 5701a00558 Update with idea on generic event support.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-09-08 08:19:16 +02:00
Joachim Nilsson 9a81bbccbb Update section on new emit <EVENT> support.
This part of the README must be completely overhauled before the
release, so much of the contents is basically just TODO or design
ideas atm.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-09-08 08:18:49 +02:00
Joachim Nilsson 2fcd0fd899 Merge branch 'wishdev-makefile-glibc-2.20' into dev 2015-09-08 08:01:12 +02:00
Joachim Nilsson 5126017c7e Merge branch 'makefile-glibc-2.20' of https://github.com/wishdev/finit into wishdev-makefile-glibc-2.20 2015-09-08 08:00:39 +02:00
John W Higgins d2ed03e74c Update Makefile for glibc-2.20+ 2015-09-07 16:56:32 -07:00
Joachim Nilsson 525aef10dd Add 'initctl show' as alias for 'initctl status', for convenience.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-09-06 20:45:56 +02:00
Joachim Nilsson 57031071fb Fix missing "libite/lite.h" include.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-09-06 20:43:28 +02:00
Joachim Nilsson 0bd57a7826 Fix missing overwrite argument to setenv().
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-09-02 16:05:42 +02:00
Joachim Nilsson 814ffd9259 Fix missing default PATH for root and non-root users.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-09-02 14:50:46 +02:00
Joachim Nilsson f94db7bceb Remove local macros for bitmanip, now provided by libite
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-08-22 14:00:12 +02:00
Joachim Nilsson 98ba5955c8 README: Document initial ideas for future event support
Writing TODO's in the README makes it a promise ...

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-08-22 13:56:36 +02:00
Joachim Nilsson 52c51f16ed Move to use dockerized/faster build at Travis-CI
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-08-22 13:55:07 +02:00
Joachim Nilsson 3b1e652d40 libite: Upgrade libite to v1.0.0+, lots of fixes
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-08-22 13:53:50 +02:00
Joachim Nilsson d6490df9a3 inetd.c: Improve error detection in inet port conversion.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-07-10 19:10:28 +02:00
Joachim Nilsson 0fd9aa6497 The atonum() function is now provied by libite.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-07-10 19:06:51 +02:00
Joachim Nilsson b30678bbe9 Functions makepath() and ifconfig() now provied by libite.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-07-10 18:33:47 +02:00
Joachim Nilsson 1db144c677 Functions pidfile_read() and pidfile_poll() now provied by libite.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-07-09 03:24:20 +02:00
Joachim Nilsson 8b8ddc43b5 Refactor: Further API cleanup -- hide svc_t internals.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-06-29 01:50:21 +02:00
Joachim Nilsson 838ec0423d Fix: Loss of dynamic service on second reload (unmodified).
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-06-29 01:25:45 +02:00
Joachim Nilsson 05a8ace030 Add support for 'initctl emit EVENT' for more granular control.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-06-29 00:58:12 +02:00
Joachim Nilsson a05f920292 Refactor: Cleanup internal API
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-06-28 17:23:07 +02:00
Joachim Nilsson d8b331d737 Update .gitignore
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-06-28 17:20:56 +02:00
Joachim Nilsson 381a32bf8a Upgrade libite to fix copyfile() bug.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-06-22 22:43:04 +02:00
Joachim Nilsson ee9e49f412 Makefile: Do not fail anymore on warnings, not useful in production.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-06-22 22:04:14 +02:00
Joachim Nilsson ff2df8ce5c Upgrade libite, handle missing O_TMPFILE gracefully.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-06-22 22:03:32 +02:00
Joachim Nilsson e595e9da5f Upgrde to libite version with new tempfile()
The tempfile() replacement in Finit leaked temporary files in /tmp.
The mkstemp() based implementation does not remove temporary files
when they are closed.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-06-22 21:44:46 +02:00
Joachim Nilsson f1807a32ca Make it possible to distribute finit.h in 'make dev-install'
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-06-22 15:12:20 +02:00
Joachim Nilsson 9a6ab331a6 Refactor: Move rest of finit.h settings to configure script.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-06-22 15:12:20 +02:00
Joachim Nilsson 70af5d7f8d Refactor: Move HAVE_DBUS and CONSOLE to configure script.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-06-22 15:12:20 +02:00
Joachim Nilsson 36c59e77b4 Fix broken SYSROOT and add it to configure script.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-06-22 15:12:20 +02:00
Joachim Nilsson 57b167f9aa Refactor: Move root fs remount setting to configure script.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-06-22 15:12:20 +02:00
Joachim Nilsson 155ae15390 Refactor: Move random seed config to configure script.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-06-22 15:12:20 +02:00
Joachim Nilsson 06a1a3c839 Refactor: Move default runlevel to configure script.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-06-22 15:12:20 +02:00
Joachim Nilsson 42f3d4dc79 Refactor: Move DEFUSER and DEFHOST to configure script
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-06-22 15:12:20 +02:00
Joachim Nilsson 8e12dba8d9 Refactor: Move conf.c declarations from finit.h --> conf.h
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-06-22 15:12:20 +02:00
Joachim Nilsson 589a7ea8a5 Always run HOOK_SVC_RECONF on SIGHUP/reload
When Finit receives SIGHUP or a reload command all services listed in
/etc/finit.d/*.conf are first stopped and then started again.  I.e.,
removed/changed services are stopped and then new/changed services are
started again.  In between we call HOOK_SVC_RECONF.  It should always be
called, even though no services were removed/changed/added.  This to
allow plugins connected to that hook may need to run as intended.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-06-22 15:12:20 +02:00
Joachim Nilsson e5732f24d3 Followup to tempfile(): template must be writable.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-06-22 15:12:20 +02:00
Joachim Nilsson 3d0e58ebcd Followup to tempfile(): paranoid umask as well ...
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-06-21 22:25:33 +02:00
Joachim Nilsson 162b394726 Replace insecure tmpfile() with mkstemp() based local tempfile()
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-06-21 21:54:24 +02:00
Joachim Nilsson c6a9fa3b98 initctl: Order inetd filters same as in .conf file.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-06-21 19:06:07 +02:00
Joachim Nilsson e04c73bab8 initctl: Add UDP/TCP to presentation of inetd services in verbose mode.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-06-21 18:55:05 +02:00
Joachim Nilsson ac0edc9b37 initctl: Fix broken presentation of inetd services in verbose mode.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-06-21 18:54:29 +02:00
Joachim Nilsson 59731988fd initctl: Add support for showing current runlevel
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-06-21 18:30:01 +02:00
Joachim Nilsson d0da3b8b98 Followup to 'initctl with process name as well as JOBID'
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-06-21 17:56:41 +02:00
Joachim Nilsson be074abce8 Followup libite submodule, use https not git proto.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-06-21 16:29:16 +02:00
Joachim Nilsson 577622c945 Add support for calling initctl with process name as well as JOBID
This patch makes it possible to communicate process name or JOB[:ID]
from initctl to Finit.  When the process name translates into a service
with multiple instances Finit applies the requested command to all
instances.  For example, two Dropbear SSH services running on two
different ports, calling `initctl stop dropbear` stops both services.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-06-21 15:54:47 +02:00
Joachim Nilsson 5d2172eac8 Upgrade to libuev -dev.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-06-18 08:44:41 +02:00
Joachim Nilsson 276cda9a4d Install -dev files for both libite and libuev, needed for external plugins.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-06-18 08:44:15 +02:00
Joachim Nilsson bafdf0007f Helper macros moved to libite/lite.h
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-06-18 02:26:53 +02:00
Joachim Nilsson 064e94e030 Add/readd libite, now as a separate submodule.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-06-18 02:26:47 +02:00
Joachim Nilsson c00ac21fe2 Remove libite and chomp() in preparing for ... libite.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-06-18 01:11:22 +02:00
Joachim Nilsson 164fe12685 Update ChangeLog
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-06-17 14:27:34 +02:00
Joachim Nilsson e7dad9a770 Add inetd.h to distributed headers, needed for external plugins.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-06-17 14:07:35 +02:00
Joachim Nilsson 02e5c868ba Makefile: Declare dependencies better, for parallel builds
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-06-17 14:07:30 +02:00
Joachim Nilsson 66f472bb05 service_start(): Make sure to collect the run child.
Fix side effect with run stanza children not being collected if finit is
not run in verbose mode.  Regression introduced in release cycle.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-06-17 13:36:36 +02:00
Joachim Nilsson 7b894fcf52 Prune and relocate #include files.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-06-17 13:36:36 +02:00
Joachim Nilsson 0de4fb0cbf inetd: Fix naming of built-in service on custom port.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-06-17 13:36:36 +02:00
Joachim Nilsson 231539cd7d Move all custom banner() handling to configure script.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-06-17 13:36:36 +02:00
Joachim Nilsson 195f17ae08 TODO: Markdown syntax fixes.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-06-17 13:36:36 +02:00
Joachim Nilsson 54ace1a6cf README: Further updates and corrections to inetd syntax.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-06-17 13:36:36 +02:00
Joachim Nilsson 1f19b50846 Fix Coverty CID #96208: Unchecked return value from library.
Replace `remove()` with our own `erase()` which checks the return value
and warns on actual real failure.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-06-17 13:36:17 +02:00
Joachim Nilsson 6c58a7d774 Fix Coverty CID #96209: Dereference NULL return value.
The new iterators `svc_inetd_iterator()` and `svc_dynamic_iterator()`
used unsafe constructs that could cause them, at least the latter, to
dereference a `NULL` pointer.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-06-17 13:36:06 +02:00
Joachim Nilsson dbcece81ea Fix Coverty CID #96210: Argument cannot be negative.
We must check the return value from `accept()`, it may fail.  Also, we
should probably retry the syscall in some cases ...

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-06-17 13:36:06 +02:00
Joachim Nilsson 70f4d99922 Fix Coverty CID #96211: String not NUL terminated.
When receiving a start/stop/reload/restart request from initctl we must
make sure to validate and NUL terminate the job ID.  The `read()` API
does not NUL terminate strings for us and we cannot rely on `initctl` or
any other external API user to do so for us.

This patch improves error and boundary checking.

- Use memcpy() + hard termination instead.
- Fix use of strchr() on possibly non-NUL terminated string.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-06-17 13:35:10 +02:00
Joachim Nilsson ee6d524bc8 Update ChangeLog and README for release.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-06-15 22:43:03 +02:00
Joachim Nilsson d9055c3965 Fix build/install --with-plugins='a b' -- only build/install a and b
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-06-15 16:55:17 +02:00
Joachim Nilsson 03573b41ca Add support for a deny filter syntax to inetd services
This patch changes the syntax for custom inetd services and adds support
for deny filters.  The new syntax is:

    inetd service/proto[@iface,!iface,...] </path/to/cmd | internal[.service]>

This means the second column now defines what@from and the third to/what
process.  For internal services on a custom port the internal.service
syntax must be specified, so Finit can properly bind the inetd service
to the correct plugin.  Here follows a few examples:

    inetd time/udp                    wait [2345] internal                -- UNIX rdate service
    inetd time/tcp                  nowait [2345] internal                -- UNIX rdate service
    inetd 3737/tcp                  nowait [2345] internal.time           -- UNIX rdate service
    inetd telnet/tcp@*,!eth1,!eth0, nowait [2345] /sbin/telnetd -i -F     -- Telnet service
    inetd 2323/tcp@eth1,eth2,eth0   nowait [2345] /sbin/telnetd -i -F     -- Telnet service
    inetd 222/tcp@eth0              nowait [2345] /sbin/dropbear -i -R -F -- SSH service
    inetd ssh/tcp@*,!eth0           nowait [2345] /sbin/dropbear -i -R -F -- SSH service

Access to telnet on port `2323` is only possible from interfaces `eth0`,
`eth1` and `eth2`.  The standard telnet port (`23`) is available from
all other interfaces, but also `eth2`.  The `*` notation used in the ssh
stanza means *any* interface, however, here `eth0` is not allowed.

NOTE: This patch breaks syntax compatibility with Finit v1.12!

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-06-15 14:15:39 +02:00
Joachim Nilsson b0c759e518 Add missing file api.c
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-06-15 14:06:55 +02:00
Joachim Nilsson 1a1f24721f Refactor: introduce telinit and a new initctl tool w/ API
- Reduce size of `helpers.c`, for linking against new `initctl` tool,
  by moving out functions to `pid.c` and `exec.c`
- Add `AF_UNIX` API to Finit, to complement old `/dev/initctl` FIFO
- Let old FIFO API be used by init/telinit: `init <q | 1-9>`
- Move all advanced initctl code from `client.c` to `initctl.c`, yes
  its a bit confusing to call the *new* tool the same as the old FIFO
  but this is more in line with what, e.g Upstart does.
- Move all advanced server side code from `plugins/initctl.c` to `api.c`
- Update TODO with upcoming inetd syntax change and dynamic events.
- Temporarily fix display of inetd services from `initctl status -v`

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-06-13 12:26:16 +02:00
Joachim Nilsson 66edb42e06 Upgrade to libuev v1.2.0
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-06-09 14:57:41 +02:00
Joachim Nilsson 4e904142cb configure: Reverse kernel-quiet, enable --> disable, enabled by default.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-06-08 18:08:08 +02:00
Joachim Nilsson 7b5d56df98 TODO: Document proposal for dynamic event framework
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-06-08 18:07:40 +02:00
Joachim Nilsson 1d58f4abbe initctl: New symlink to finit binary, document functions in README.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-06-08 18:06:55 +02:00
Joachim Nilsson 24e1d284ad Add support for finit <stop|start|reload|restart> JOB
This patch further extends the capabilities of the client with the
ability to control the running state of services:

    finit <stop|start|reload|restart> JOB

Since services can now exist with multiple instances the concept of
"jobs" is introduced in this patch.  A job is a numeric identifier of
the form `NUM[:NUM]`, the latter `:NUM` is the new instance syntax
introduced earlier.  See the output of `finit status` for the JOB id.

Also, with the introduction of multiple instances we broke support for
multiple related inetd services.  This became obvious when the shiny new
`finit status` was tested ... hence, this patch also contains fixes to
the inetd support.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-06-08 08:32:49 +02:00
Joachim Nilsson 720324b256 Change syntax for multiple instances: #ID --> :ID
Turns out that #ID syntax for multiple instances, introduced in cb07556,
was very cumbersome to reference from the shell command line in the new
Finit client.  This patch changes the syntax from #ID to :ID, which also
means that listing services/jobs in the shell will look like JOB:ID.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-06-08 01:07:41 +02:00
Joachim Nilsson 534979e6c7 inetd_match(): Fix bug in matcher, make sure to also compare protocol!
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-06-08 00:54:54 +02:00
Joachim Nilsson 6a27ad8997 Improve output from 'finit status'
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-06-07 16:26:11 +02:00
Joachim Nilsson 6d3972cca8 Add --enable-kernel-quiet to configure, delayed quiet after initial boot.
... with the additional twist that the kernel command line option
'quiet' also gets to play.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-06-07 16:20:23 +02:00
Joachim Nilsson f8d608107c Allow quiet mode to disable banner, also simplify default banner.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-06-07 16:06:23 +02:00
Joachim Nilsson 0dd97de046 Add --enable-quiet to configure, makes Finit real quiet.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-06-07 15:57:11 +02:00
Joachim Nilsson 2026486fda Refactor: Cleanup and expand client code to support <version|q|reload|debug>
Further refactoring of the client code.  Supported commands:

- debug:   Toggle PID 1 debug flag
- version: Show Finit version or custom header string
- reload:  Reload config files in /etc/finit.d/, same as SIGHUP

Also supported is the legacy 'init q' command, to reload config.

The 'status' command now supports an optiona '-v', either as an
argument to init itself, or as argument to the command.  When it
is given 'status' lists verbose information about all services.
Currently only the service arguments are listed.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-06-07 12:11:07 +02:00
Joachim Nilsson 811bd75eab Refactor: Move client code to separate file and add 'status' command.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-06-07 12:09:55 +02:00
Joachim Nilsson 97a48ec5fb Refactor: move advanced service methods from svc.c --> service.c
This patch refactors svc.c into two files: svc.c now as a low-level
svc_t API and service.c for the more advanced rest.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-06-07 03:23:46 +02:00
Joachim Nilsson 8e9a5ee678 Update README on Inetd services and cleanup TODO.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-06-06 11:30:38 +02:00
Joachim Nilsson 7236e8c6a3 conf.c: Clarify comments, also include file paths must now be absolute.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-06-06 11:29:53 +02:00
Joachim Nilsson 2c1f3b1f7a Make sure to also reload all .conf files in /etc/finit.d/ when changing runlevel.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-05-31 22:45:30 +02:00
Joachim Nilsson f5584ecc3c Add two new hook points: HOOK_SVC_RECONF and HOOK_RUNLEVEL_CHANGE.
These two new hooks run when SIGHUP is received and when changing
system runlevel.  The hooks are called when all services have been
stopped, just before starting up new/modified services.  Making it
the perfect hook for reconfiguring the system/hardware before new
services or modified services are started up again.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-05-31 22:07:46 +02:00
Joachim Nilsson e83f4ab4bf TODO: Fixed some items.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-05-31 01:58:20 +02:00
Joachim Nilsson fa89370517 Fix pid_get_name() when NULL buffer is provided.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-05-31 01:58:20 +02:00
Joachim Nilsson 2cba0c73be Fix for unwanted zombies ...
When receiving SIGCHLD we must reap *all* children.  We only receive one
signal, but multiple processes may have exited.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-05-31 01:58:20 +02:00
Joachim Nilsson cb075560ed Add support for multiple instances of the same command
This patch adds support for starting and supervising multiple
services (run, task, or service) using an extra #ID number.

service #1 [2345] /sbin/httpd -f -h /http -p 80   -- Web server
service #2 [2345] /sbin/httpd -f -h /http -p 8080 -- Old web server

Also included in this patch is a fix for endless respawn of faulty
services.  For instance, a buggy daemon that crashes repeatedly will now
be stopped after 10 respawns.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-05-31 01:58:20 +02:00
Joachim Nilsson 687f52b0b5 Add support for adding/removing services from /etc/finit.d at runtime.
This patch adds support for adding and removing services from Finit at
runtime.  Configuration file stanzas for service, run and task may now
be written to files in /etc/finit.d/*.conf, using the exact same syntax
as before in /etc/finit.conf.  When a file is added, removed or modified
the user may simply SIGHUP Finit (PID 1) to activate the changes.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-05-31 01:55:39 +02:00
Joachim Nilsson 24051ab2fb TODO: Update with plan for dynamic services being loaded from /etc/finit.d
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-04-27 08:10:11 +02:00
Joachim Nilsson 9139afd318 Bump version for -dev cycle.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-04-25 10:18:40 +02:00
Joachim Nilsson 71ecead5b7 Make the 'init <CMD | RUNLEVEL>' commands synchronous.
When a user changes runlevel, or wants to reload the config, we want the
command to return only when the operation has completed.  For instance,
rolling in a new system configuration in runlevel 1 requires that we are
sure we've actually entered that runlevel before rolling it in.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-04-25 10:17:46 +02:00
Joachim Nilsson 56292f27c2 Add missing FINIT_RCSD to config.mk, needed by install/uninstall.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-04-23 19:44:44 +02:00
Joachim Nilsson 14c2f612cf Rename patches --> contrib to simplify integration in 3rd party build systems.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-04-23 11:40:48 +02:00
Joachim Nilsson e9506aec1c .travis.yml: Update Travis build script to include configure
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-03-10 22:49:52 +01:00
Joachim Nilsson d2eb46c173 Fix last part of issue #8: Libite install problem with --enable-static
Skip install of .so libs when user has configured with --enable-static

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-03-10 22:12:26 +01:00
Joachim Nilsson 0d733ad234 Merge pull request #9 from therealprologic/disable_plugins
Add a --disable-plugins option to ./configure (Fixes #8)
2015-03-10 22:05:34 +01:00
James Mills 4955e05882 Add a --disable-plugins option to ./configure (Fixes #8) 2015-03-11 07:04:38 +10:00
Joachim Nilsson c3fcfe7e4e README: Update with info on new configure script.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-03-10 11:20:39 +01:00
Joachim Nilsson 32587d341c Overhaul build system and add support for disabling inetd support.
This patch adds support for a configure script and with it
support for disabling inetd support.  See the output from

    ./configure --help

* Add configure script
* Sprinkle #ifdef fairy dust on svc.c when inetd support is disabled
* Use GCC built-in autodep calculator (-MMD -MP)
* Fix name space issue with include files, use relative paths
* Disable username/group name to uid/gid functions in static builds
* Bug out (error) if a user tries to build the bootmisc plugin static

Possibly fixes GitHub issue #5 and issue #6.

NOTE: The static build has not received any testing at all!

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-03-10 10:25:46 +01:00
Joachim Nilsson a74b640507 Initial support for building Finit statically (incomplete)
This patch adresses issue #5.  However, there still remains a few issues
to work around before Finit can be built completely standalone.

    $ make clean all STATIC=1
    LINK    finit
    helpers.o: In function `getgroup':
    helpers.c:(.text+0x10a7): warning: Using 'getgrnam' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
    helpers.o: In function `getuser':
    helpers.c:(.text+0x108e): warning: Using 'getpwnam' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
    inetd.o: In function `getent':
    inetd.c:(.text+0x127): warning: Using 'getprotobyname' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
    inetd.c:(.text+0xce): warning: Using 'getservbyname' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking

The problem is the NSS plugins and similar issues that prevent static
linking when using the above functions.  See issue #5 for more on this.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-03-06 21:58:56 +01:00
Joachim Nilsson 52664791f5 Upgrade to libuev with support for static-only builds.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-03-06 21:34:46 +01:00
Joachim Nilsson cf651df744 Bump version for v1.12 release.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-03-04 17:00:37 +01:00
Joachim Nilsson 807df44769 finit.conf: Update sample config with some example inetd services.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-03-04 16:59:53 +01:00
Joachim Nilsson f97bc83ac1 Update libuev to v1.1.0 +1, with .gitignore update.
This commit prevents false warnings about untracked files in libuev.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-03-04 16:14:18 +01:00
Joachim Nilsson daa299721d inetd.c: Check for SO_REUSEPORT capability in system first.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-03-04 15:54:13 +01:00
Joachim Nilsson ec90e3dac3 Update ChangeLog before release.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-03-04 15:32:49 +01:00
Joachim Nilsson 5ddd5c15a5 inetd.c:spawn_socket() - Set socket options for reusing address and port
Without this patch binding to sockets when restarting them fails.  This
was found when quickly changing between runlevels where a service runs,
not runs, then back to a runlevel where is shall run.

Also, refactor previous setsockopt() call to use new common macro.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-03-04 15:21:43 +01:00
Joachim Nilsson 957586db09 inetd.c:inetd_dgram_peek() - Fix reading inbound UDP interface.
There seems to have been a regression from earlier when this worked.
I'm sure it worked ... or am I?  This patch makes the whole thing look
a lot more sane, so I wonder ... might have worked in my unit tests on
x86, but not when I cross-compile to ARM.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-03-04 15:15:03 +01:00
Joachim Nilsson e0c8a7df66 inetd.c: Shutdown sockets properly before closing them.
When changing runlevels netstat still listed closed sockets as being
open and listening.  With this patch all sockets are properly shut down
before we close them.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-03-04 14:45:21 +01:00
Joachim Nilsson c769fbda0f svc.c: Add debug to svc_runlevel().
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-03-04 14:45:04 +01:00
Joachim Nilsson 1f860164f4 initctl: Make sure to open fifo with CLOEXEC
With O_CLOEXEC we prevent forked+exec'ed children from accessing the
initctl fifo via that socket.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-03-04 14:43:06 +01:00
Joachim Nilsson e29c5c069b TODO: Minor update.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-03-04 11:49:28 +01:00
Joachim Nilsson 872d0d24e7 inetd.c: Only ever allow respawn if correct runlevel.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-03-04 11:48:16 +01:00
Joachim Nilsson b644f6f635 plugins/initctl.c: Minor debug updates.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-03-04 11:47:14 +01:00
Joachim Nilsson 510d15195c plugins.c:generic_io_cb() -- Stop watcher before running callback
Stop event watcher before running callback, the plugin may manipulate
the descriptor and cause the kernel into a EPOLLHUP frenzy.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-03-04 11:46:32 +01:00
Joachim Nilsson 7ad4bce487 Upgrade to libuEv v1.1.0 for error handling fixes.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-03-04 11:02:01 +01:00
Joachim Nilsson 703b7537cf Refactor inetd support to add support for switching runlevels.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-03-01 02:35:30 +01:00
Joachim Nilsson 9cb6c88f34 Spellchecks, cleanup and simplify intro.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-02-27 10:02:08 +01:00
Joachim Nilsson 97068223ff CHANGELOG: Add user-friendly info on the 1.12 release.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-02-27 00:14:49 +01:00
Joachim Nilsson 1de5777f7e README: Update with new inetd support.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-02-27 00:14:14 +01:00
Joachim Nilsson aff11d83d8 tty.c: Let fallback shells be consoles, improved job control etc.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-02-26 18:57:17 +01:00
Joachim Nilsson 335f09726f conf.c: Slight update in TTY fallback behavior.
If no tty is configured in finit.conf, only use FALLBACK_SHELL (usually
/bin/sh on UNIX) when no console is configured either.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-02-26 18:57:10 +01:00
Joachim Nilsson 12c470667f Only restart daemons when getting SIGCONT after SIGSTOP
Fix `restart_any_lost_procs()`, called when finit recovers from being
stopped for a while.  This function should not restart task/run/inetd
services when called -- must check for type `SVC_CMD_SERVICE` when
iterating over all registered `svc_t`, just like a regular lost pid.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-02-26 16:55:15 +01:00
Joachim Nilsson 71ac8bb802 Set hostname early, so boostrap processes, e.g., syslog can use it.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-02-26 16:47:55 +01:00
Joachim Nilsson fc9758da8e Fix Coverity CID #87811 Double close
Fix double close of TCP socket introduced in GIT ded4b39,
replaced with closing all open stdio descriptors, which
shouldn't really be needed.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-02-26 16:39:30 +01:00
Joachim Nilsson 216701ce3c Attempt to fix Coverity CID #87810 Dereference null return value
Fixes, or rather works around the Coverity warning of possible NULL
pointer dereference.  (Not an error.)

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-02-26 16:34:38 +01:00
Joachim Nilsson 5d5075954e TODO: Add some ideas on pmon to watchdog chapter.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-02-26 16:14:29 +01:00
Joachim Nilsson ded4b3926e Refactor inetd support, now with support for custom ports and iface filtering
This patch adds support for custom port and interface filtering to inetd
services, in a very condensed syntax:

    inetd ssh@eth0:222/tcp nowait [2345] /usr/sbin/sshd -i
    inetd ssh@eth1:22/tcp  nowait [2345] /usr/sbin/sshd -i

In this example eth0 and eth1 are allowed inbound interfaces for SSH
connections, on port 222 and 22, respectively.  Attempting to connect
from any other interface is denied.  Also, if the system is not in
runlevel 2, 3, 4, or 5, ports 222 and 22 will not even be opened.

If eth0 is your upstream interface you may want to avoid using the
default port.  To run ssh on port 222, and all others on port 22:

    inetd ssh@eth0:222/tcp nowait [2345] /usr/sbin/sshd -i
    inetd ssh/tcp          nowait [2345] /usr/sbin/sshd -i

This actually adds a deny rule for eth0 on ssh/tcp, implicitly.  You can
even list the services in the reverse order with the same result:

    inetd ssh/tcp          nowait [2345] /usr/sbin/sshd -i
    inetd ssh@eth0:222/tcp nowait [2345] /usr/sbin/sshd -i

There is no specific deny syntax available yet, see the TODO file for
more details on how this can be implemented.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-02-26 01:37:11 +01:00
Joachim Nilsson 365932510f Update dreamworld.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-02-25 10:13:44 +01:00
Joachim Nilsson 888128e56b README: Slight cleanup to make it more readable w/o Markdown.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-02-25 10:13:12 +01:00
Joachim Nilsson 2adec264af Replace atoi() with atonum() --> better error handling.
Friends don't let friends use atoi().

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-02-25 10:12:15 +01:00
Joachim Nilsson ccdab464c3 Fix Coverity CID 87570: Unchecked return value from setsockopt()
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-02-18 23:10:30 +01:00
Joachim Nilsson a7353678a3 Actually fix Coverity CID 56281: dlopen() resource leak
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-02-18 22:59:32 +01:00
Joachim Nilsson ad8ae4af91 Fix Coverity CID CID 56281: Resource leak (RESOURCE_LEAK)
Initial support for unloading plugins.  Currently we only save dlopen()
handle.  The plugin_unregister() function itself is never called atm.
This should at the very least make Coverity happy.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-02-18 22:39:54 +01:00
Joachim Nilsson dd7f0ce090 Fix Coverity CID 87571: Uninitialized scalar variable (UNINIT)
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-02-18 22:18:02 +01:00
Joachim Nilsson 8c955836dd Load plugins before finit.conf is parsed, needed by internal inetd services
This patch is slightly sub-optimal, since it will causes us to load all
availble plugins, not just those referenced by finit.conf.  However, in
the short term perspective we need to reference internal inted services
provided by plugins from finit.conf, so the dependency order is clear.

In the midterm perspective we want to add support for SIGHUP to reload
finit.conf, but not plugins.  So again, this is an OK patch.

One fix would be to allow loading of all plugins, parse finit.conf and
then unload all unused plugins before continuing.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-02-18 22:04:36 +01:00
Joachim Nilsson 183022ebe4 Initial support for RFC 868 (rdate), internal inetd service.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-02-18 22:04:31 +01:00
Joachim Nilsson 33be077f92 TODO: Remember to support non-getty logins.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-02-18 16:53:00 +01:00
Joachim Nilsson 6a137fa73c TODO: Update with info on internal inetd services, like time, echo etc.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-02-18 15:17:00 +01:00
Joachim Nilsson 25c85dfc88 Add markdown hinting for Emacs.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-02-16 10:27:16 +01:00
Joachim Nilsson 58cc96115c Initial support for figuring out inbound interface for inetd connections
This patch adds initial support (only SOCK_STREAM verified!) for
figuring out the inbound interface for inetd service connections.

The intention is to use this later on for a very simple tcpwrappers
replacement, e.g: `deny telnet eth0 eth3`

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-02-16 10:26:54 +01:00
Joachim Nilsson b4b63d3722 Trap segfaults caused by service callbacks in separate process context
This patch traps segfaults caused by 3rd party service callbacks in a
separate process context.  Effectively preventing a single programming
mistake from taking down the entire system.  Previously it was up to the
callback coder to write error free code so that PID 1 did not crash.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-02-16 10:21:03 +01:00
Joachim Nilsson d6efe85a57 Silence launch of inetd services.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-02-09 00:57:21 +01:00
Joachim Nilsson 51b27e8372 Revert "Use vfork() instead of fork() before exec()"
This reverts commit 074686b520.  Which
turned out to not work so well after all.  For instance, launching TTYs
in a background process completely blocked inetd services from even
starting up listening sockets ... proper fork seems to work fine though.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-02-09 00:45:09 +01:00
Joachim Nilsson cac612c485 Remember to fix these ...
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-02-09 00:43:33 +01:00
Joachim Nilsson a5b9f566b3 Initial support for inetd/on-demand services \o/
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-02-09 00:43:15 +01:00
Joachim Nilsson 0d098616e8 Whitespace changes only
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-02-01 17:28:36 +01:00
Joachim Nilsson 63722a20ac Allow mixed case configuration commands in finit.conf
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-02-01 17:27:18 +01:00
Joachim Nilsson 6f6ab6bc33 Minor whitespace fixes
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-01-29 12:34:30 +01:00
Joachim Nilsson 7f0a85c106 Updated inetd syntax and add possible bug, needs investigating.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-01-29 12:33:35 +01:00
Joachim Nilsson 46ddf4bcc6 Commence new -dev phase.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-01-24 23:56:52 +01:00
Joachim Nilsson f5ab075f9d Upgrade libuEv to v1.0.4
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-01-24 23:54:53 +01:00
Joachim Nilsson 9b361864fa Fix make dist target for v1.11 release.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-01-24 16:16:13 +01:00
Joachim Nilsson 41b0dc41a6 Update ChangeLog for v1.11 release.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-01-24 16:13:46 +01:00
Joachim Nilsson cab339c857 Simplify build example.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-01-24 16:07:55 +01:00
Joachim Nilsson dcb42602c9 Cleanup README for release.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-01-24 16:04:54 +01:00
Joachim Nilsson 9e446557b4 Change Coverity Scan branch to use 'dev' instead of master.
We don't want to run out of scan tokens for every README update.  This
also means the introduction of a new workflow.  All new development must
be staged to the dev branch before being merged to master.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-01-24 15:29:16 +01:00
Joachim Nilsson a3d76c58a4 Expand on how plugins can interact with system bootstrap.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-01-21 19:34:01 +01:00
Joachim Nilsson e0e0581d10 Trim slogan ...
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-01-21 13:29:35 +01:00
Joachim Nilsson ef75d5ec31 Cleanup Introduction and add Bootstrap section.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-01-21 13:25:24 +01:00
Joachim Nilsson dfeabd8bae Improve inetd syntax proposal
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-01-21 13:15:16 +01:00
Joachim Nilsson 7aa687bad9 Reindent to more 'pure' Markdown and remove fixed event lib TODO.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-01-19 21:24:06 +01:00
Joachim Nilsson c2ea2c1193 Reindent to more 'pure' Markdown.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-01-19 21:12:14 +01:00
Joachim Nilsson 291b22e987 Give up and add actual link to GIT commit.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-01-18 23:46:21 +01:00
Joachim Nilsson a091b69dd6 Another try ...
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-01-18 23:45:16 +01:00
Joachim Nilsson 887c84a0d1 Attempt to fix GIT commit auto linking.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-01-18 23:44:27 +01:00
Joachim Nilsson 5009d54ab8 Reindent to more 'pure' Markdown.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-01-18 23:43:04 +01:00
Joachim Nilsson 840ade6da7 Bump version for next release, fix make dist and rename NEWS --> CHANGELOG
- Bump version for coming 1.11 release
- Update `make dist` to use Kentzo's `git-archive-all` from
  https://github.com/Kentzo/git-archive-all
- Rename NEWS --> CHANGELOG and update for coming release
- Update CHANGELOG with info on the libuEv migration

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-01-18 23:22:39 +01:00
Joachim Nilsson 030aa70842 Simplify.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-01-18 22:29:34 +01:00
Joachim Nilsson dea3ae857b Steal controlling TTY on fallback console to enable job control.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-01-18 22:25:04 +01:00
Joachim Nilsson 9f5172b0d1 Try removing delayed start of TTYs, should not be needed anymore.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-01-18 21:40:09 +01:00
Joachim Nilsson e0529a5597 Unblock all signals blocked by finit when starting children
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-01-18 21:40:05 +01:00
Joachim Nilsson 425cd17e57 Initial conversion to use libuEv for all event handling.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-01-18 00:53:14 +01:00
Joachim Nilsson 0669a9cb81 Fix missing #include for copyfile()
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-01-18 00:46:06 +01:00
Joachim Nilsson 5e040449c4 Add libuEv as submodule for event handling.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-01-07 02:59:21 +01:00
Joachim Nilsson 074686b520 Use vfork() instead of fork() before exec()
If running on older Linux systems, or any BSD UNIX, vfork()
is more efficient when we are about to call exec() anyway.

For more info on vfork() vs fork(), see Stack Exchange:
http://stackoverflow.com/questions/4259629/what-is-the-difference-between-fork-and-vfork

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-01-06 23:38:47 +01:00
Joachim Nilsson d40f52357e Restructure and add section on Watchdog process supervision
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-01-06 21:45:14 +01:00
Joachim Nilsson 076f77a31b Update TODO: more on inetd and at support.
Also a minor fix to the README.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-01-06 20:54:52 +01:00
Joachim Nilsson 8f1c16a8a5 Update TODO with section on Cron.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-01-01 02:04:50 +01:00
Joachim Nilsson b149dbc73e Update TODO
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-01-01 00:11:44 +01:00
Joachim Nilsson aa8d6a7294 Bump version for 1.10 release.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-11-27 22:33:24 +01:00
Joachim Nilsson a94dde403f Update NEWS to Markdown syntax and add info on next release.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-11-27 09:42:49 +01:00
Joachim Nilsson 9bb7e7b014 Change NEWS documentation from reST to Markdown
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-11-27 09:19:33 +01:00
Joachim Nilsson 02a97e8d7d Fix various problems with unchecked return values from syscalls.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-11-27 00:12:07 +01:00
Joachim Nilsson def759fe41 run_interactive(): Fix a potential file descriptor leak.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-11-26 23:45:20 +01:00
Joachim Nilsson 939cfc2476 pidfile_read(): Reindent.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-11-26 23:44:00 +01:00
Joachim Nilsson 7f2c73468f libite/rsync.c: Fix build regression from previous commit.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-11-26 23:37:04 +01:00
Joachim Nilsson 81a368f710 Fix problem with unchecked return value of mkdir(), wrap in makedir() macro.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-11-26 23:27:15 +01:00
Joachim Nilsson 4e975e4974 plugin.c:load_one() - Comment on resource leak, we never unload plugins atm.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-11-26 23:24:49 +01:00
Joachim Nilsson a296c2dd00 pidfile_read(): Fix potential integer overflow when reading PID
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-11-26 23:02:54 +01:00
Joachim Nilsson 5ff7994852 touch(): Check return value of mknod(), report error if errno != EEXIST.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-11-26 22:57:23 +01:00
Joachim Nilsson 1bdcef9a2c run_interactive(): Fix file descriptor leak when debug is enabled.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-11-26 22:49:31 +01:00
Joachim Nilsson f621117eb9 README: Update section on plugins with info on hooks and I/O plugins.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-11-26 18:48:25 +01:00
Joachim Nilsson 83cec7129a run_interactive(): Fix copy-paste bug introduced in 06b33c5.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-11-26 17:58:50 +01:00
Joachim Nilsson 06b33c58fd run_interactive(): Fix descriptor leak.
Make sure to close dup()'ed descriptors when we're done with them.
Thanks to Coverity Scan for finding this nasty one!

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-11-26 17:30:58 +01:00
Joachim Nilsson 8ce39f592c procname_kill(): Fix possible resource leak and let's use opendir() errno
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-11-26 17:22:55 +01:00
Joachim Nilsson d37c451e81 svc_start(): Fix out of bounds write to args[] array.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-11-26 17:20:27 +01:00
Joachim Nilsson a7ff1a61d5 svc_start(): Fix swapped arguments to dup2() and add close(fd), descriptor leak.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-11-26 17:17:47 +01:00
Joachim Nilsson 8349909f60 helpers.c:run_interactive() - Check arguments and return values better.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-11-26 17:08:00 +01:00
Joachim Nilsson 3a2cf30f47 README: Minor touch up.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-11-26 16:41:04 +01:00
Joachim Nilsson 9a3cab3645 TODO: Remove finished items now documented in README
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-11-26 16:40:43 +01:00
Joachim Nilsson 7dbc02f879 Standardize on two-space indented * for bullet lists in Markdown
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-11-26 16:13:53 +01:00
Joachim Nilsson a39f75744c Update TODO to Markdown syntax.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-11-26 16:08:59 +01:00
Joachim Nilsson 5742c6591a Change TODO documentation from reST to Markdown
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-11-26 15:59:34 +01:00
Joachim Nilsson 588901ee4c Update README to Markdown syntax.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-11-26 15:56:50 +01:00
Joachim Nilsson e30d2aae19 Change documentation from reST to Markdown
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-11-26 15:55:33 +01:00
Joachim Nilsson 463e4f12f8 Update Coverity URL and add section on hooks, plugins & callbacks.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-11-24 18:21:47 +01:00
Joachim Nilsson 01c2817005 Add support for Coverity Scan
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-11-24 13:49:18 +01:00
Joachim Nilsson 1a16aab970 queue.h: Upgrade to a newer slightly bugfiex version of OpenBSD queue.h
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-11-03 20:56:11 +01:00
Joachim Nilsson 8247344f0d helpers.c:set_hostname() - Fix resource and memory leaks.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-10-31 15:26:49 +01:00
Joachim Nilsson 2fdd64a2d8 helpers.c:run() - Fix resource and memory leaks.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-10-31 15:16:00 +01:00
Joachim Nilsson 22ed4e7f73 svc.c - Break out nested function.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-10-31 14:58:13 +01:00
Joachim Nilsson 327ac9f931 libite:rsync.c - Break out nested function.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-10-31 14:56:51 +01:00
Joachim Nilsson 5ad0c38fe8 Sanity check plugpath as well, no point in searching for plugins otherwise.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-10-30 22:11:23 +01:00
Joachim Nilsson 757911f149 Bump version for release and update copyright years.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-04-21 16:03:54 +02:00
Joachim Nilsson 35b771fb42 Add empty space for formatting.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-04-21 15:51:33 +02:00
Joachim Nilsson 720f1b0e5b Strip output when loading .conf files.
If not standard finit.conf, then we want to show just the base name.
E.g., loading first /etc/finit.conf then /etc/finit.d/services.conf

Loading configuration ............. vs
Loading services configuration ....

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-04-21 15:46:09 +02:00
Joachim Nilsson 292a3be515 lite.h: Add some helper string comparison methods.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-04-21 15:45:23 +02:00
Joachim Nilsson 5ed407e493 helpers.c: Fix mix of off-by-one errors in new print() code.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-04-21 14:09:23 +02:00
Joachim Nilsson 40988b901c Unify print_desc() & print_result() in print() and refactor ...
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-04-21 14:05:56 +02:00
Joachim Nilsson 26d49b2027 Yet another minor bugfix to new include function.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-04-21 12:05:55 +02:00
Joachim Nilsson 10386ee4de Bug fix and document new include <CONF> syntax.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-04-21 12:03:10 +02:00
Joachim Nilsson 773d2e65d6 README: Update docs on extended syntax and behavior for tty setting
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-04-21 11:17:31 +02:00
Joachim Nilsson 3e29d883fa tty.c:tty_start() - Fix strcmp() foobar from f6f2895, must use strncmp()
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-04-21 11:08:34 +02:00
Joachim Nilsson f6f2895524 Add support for a fallback shell if no tty is setup
Try to do better by the user, by default, if no tty is specified in the
finit.conf.  This way the user will at least have a way to interact with
the system and repair it.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-04-19 22:58:20 +02:00
Joachim Nilsson 62287f8fcc Add support for including .conf files.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-04-19 22:56:19 +02:00
Joachim Nilsson be3257f805 print_desc() - Allow arguments to be NULL.
Signed-off-by: Joachim Nilsson <joachim.nilsson@westermo.se>
2014-04-19 22:25:56 +02:00
Joachim Nilsson 1bf3aa528a Fix duplicate link and cleanup contact section.
Signed-off-by: Joachim Nilsson <joachim.nilsson@westermo.se>
2014-04-19 19:31:00 +02:00
Joachim Nilsson 056236c9f8 Freshen up README, TODO, and .conf example, spell check.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-04-19 19:19:57 +02:00
Joachim Nilsson 71fff76111 svc.[ch]: Fix possible out of bounds and NULL ptr deref
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-04-12 16:41:20 +02:00
Joachim Nilsson 1095724e5c libite: Fix cppcheck warnings in rsync unit test
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-04-12 16:34:57 +02:00
Joachim Nilsson e81c2f2f90 libite: Minor style cleanup of fsendfile()
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-04-12 16:21:41 +02:00
Joachim Nilsson 9f91b4c050 libite: Simplify and fix another memleak in copyfile()
- Simplify: reduce indentation depth
- Always check for error condition first, cleaner code
- Make sure buffer is always freed, use same exit everyhere
- Use readable, but still short, local variable names

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-04-12 16:11:59 +02:00
Joachim Nilsson 7ada824e3e Makefile: Add support for make check to run cppcheck
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-04-12 16:08:30 +02:00
Joachim Nilsson 7cf7591f0a run_getty(): Handle STDIO descriptors better.
The cppcheck tool raised an alert to the missing close() for
stdin when a console is opened for a getty.  This patch fixes
that warning and also makes the code slighlty more readable.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-04-12 15:15:43 +02:00
Joachim Nilsson 143a257c25 libite: Copy utility fixes and new functionality
- Add support for symlinks to copyfile()
- Fix memory leak in copy_filep()
- New function, fsendfile(), copy data between FILE streams

Also, minor whitespace and coding style cleanup.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-04-12 15:08:56 +02:00
Joachim Nilsson 1d98647c54 Add missing include for system header file
Only affects externally built plugins.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-04-12 14:31:31 +02:00
Joachim Nilsson 7cd52b36a1 Always print service start/stop at start of line
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-04-12 14:30:34 +02:00
Joachim Nilsson b033052647 TODO: Further simplify example inetd syntax.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-04-10 10:34:06 +02:00
Joachim Nilsson 4fcf2533a6 Minor indentation fix to TODO.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-04-10 10:29:06 +02:00
Joachim Nilsson a8a103a521 Update TODO with inetd proposal, and minor README cleanup.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-04-10 10:26:46 +02:00
Joachim Nilsson 12b09bb80b Improve CI status integration in README and minor cleanup.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-02-25 09:23:16 +01:00
Joachim Nilsson 49aaffcf9a Update README with CI status. 2014-02-25 00:00:43 +01:00
Joachim Nilsson afbe628f17 Travis CI integration
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-02-24 23:46:28 +01:00
Joachim Nilsson 1d6cbe31fe Initial support for restarting lost processes during norespawn
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2014-02-24 23:33:38 +01:00
Jonas Johansson cb874d7a94 Handle SIGHUP requst from service when switching runlevel
Signed-off-by: Jonas Johansson <jonasj76@gmail.com>
2014-02-24 23:33:38 +01:00
Joachim Nilsson d7598ca672 Update URL of example to new download FTP. 2013-06-08 15:37:31 +02:00
Joachim Nilsson ff8e494abd Update README with a slightly more clear and catchy intro. 2013-06-08 14:49:28 +02:00
Joachim Nilsson dfaa6dd3f8 Minor ReST syntax fix for improved display in GitHub
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2013-06-08 11:23:24 +02:00
Joachim Nilsson 849f3fbb28 Explain finit.conf commands more in README, update example .conf
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2013-06-07 14:09:46 +02:00
Joachim Nilsson 329acf24bb Bump version and start preparing docs for release of 1.8
Renamed ChangeLog to NEWS and fixed doc style to use ReST, like the
README and TODO files.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2013-06-07 09:16:00 +02:00
Joachim Nilsson bf40278131 Delay start of TTYs to let system stabilize at boot.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2013-06-06 18:19:27 +02:00
Joachim Nilsson 4f2cf52eff Minor cleanup. 2013-06-06 18:19:27 +02:00
Joachim Nilsson f96fb855ce tty: Clear PID to be able to respawn it.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2013-06-06 18:19:27 +02:00
Joachim Nilsson 65f0be8a55 Simplify banner further, let distributions patch us instead.
Revert crazy BANNER macro idea from 5ba7bc1.  It is simply too difficult to
set -DBANNER='"Some distributions specific text"' in a parent Makefile
without entering Shell/Make escape hell ... instead, downstream will
have to patch the banner() function.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2013-06-06 18:19:26 +02:00
Joachim Nilsson bcfcafdb7c tty: Use calloc() instead of malloc() to prevent uninitialized errors.
On some platforms GCC does not zero the heap. This can lead to
serious problems, e.g., tty->pid may be non-zero while never
having been started.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2013-06-06 18:19:26 +02:00
Joachim Nilsson c57bd066d1 Build fix, if ROOTDIR was set linking failed. Use TOPDIR internally.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2013-06-06 18:19:26 +02:00
Joachim Nilsson 4171fbdfd3 Store RUN_LVL in UTMP and change RUNLEVEL_BOOT from 10 to 0
Standard init implementations save current and previous runlevels
in utmp, now finit does too.  Also, the initial runlevel at boot
has changed from 10 to the more obvious 0.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2013-06-06 18:19:26 +02:00
Joachim Nilsson 0f60aa2289 Refactor TTY code to honor runlevels and use I/O plugin to watch /dev
Add support for runlevels to tty command and support for reading baud
rate and TERM variable from finit.conf.

The tty-watcher thread has been converted to a standard I/O plugin.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2013-06-06 18:19:26 +02:00
Joachim Nilsson f97aab4699 Rename stat_restart_counter --> restart_counter
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2013-06-06 18:19:18 +02:00
Joachim Nilsson 740d447442 Update Debian 6.0 example /etc/finit.conf and /etc/finit.d
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2013-06-04 13:12:53 +02:00
Joachim Nilsson 6448d6ccfa Coding style and whitespace fixes
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2013-06-04 09:25:11 +02:00
Joachim Nilsson 25cc9f3b9b Improve runlevel support by adding a bootstrap phase, also adds task/run cmd
Most systems need an early bootstrap phase for one-shot tasks and
necessary one-time probing.  This phase usually runs well before any
networking is setup.  This commit adds support for that 'S' runlevel,
and also extends the number of possible total runlevels to nine.

For the one-shot tasks that run in bootstrap two new finit.conf cmds
have been added:

   - task: For one-shot tasks that can be started in parallell
   - run:  For one-shot tasks that must run in sequence

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2013-06-04 09:25:05 +02:00
Joachim Nilsson e776838de9 Rename USE_UDEV & MDEV to SETUP_DEVFS and USE_MESSAGE_BUS to HAVE_DBUS
USE_UDEV,MDEV   => Unique SETUP_DEVFS for embedded or distro usage.
USE_MESSAGE_BUS => HAVE_DBUS

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2013-06-04 07:21:08 +02:00
Joachim Nilsson bf0cfe0693 Update and clarify TODO items, e.g., add info on new "task" and "run" stanzas
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2013-06-04 07:21:00 +02:00
Joachim Nilsson f690767507 Refactor .conf file parser and add support for runlevel N
This commit is a refactor of how arguments to finit.conf file settings
are parsed.  Not all settings are run directly, but only need the arg
for future use.  The code should be a lot easier to understand now.

Also, added support for specifying the desired runlevel in finit.conf

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2013-05-22 12:42:56 +02:00
Joachim Nilsson 4d57b14b5b Bugfix chomp() and set_hostname()
chomp():
        Removed first \n instead of last \n

set_hostname():
        If /etc/hostname exists we need to realloc the size of
        the current hostname variable. Also, only try to set
        the hostname if !NULL

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2013-05-22 12:41:59 +02:00
Joachim Nilsson 263036045a tty: Check input arguments for invalid tty before adding.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2013-05-22 12:36:19 +02:00
Joachim Nilsson 56ef3f75d3 Build: Make subdir build prettier.
The ROOTDIR variable was only set in the top-level Makefile,
so when building from a subdirectory the output was slightly
garbled.  Moved ROOTDIR declaration to common.mk.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2013-05-22 06:18:52 +02:00
Joachim Nilsson d0c902ab78 libite: Add strtonum() from OpenBSD
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2013-05-21 19:55:41 +02:00
Joachim Nilsson 5ba7bc1fdf Cleanup and simplify boot process messages
- Remove indentation of module loading and device node creation
- Clarify that we load kernel modules
- Clarify that we load Finit plugins
- Remove cls()
- Remove verbose condition for echo()
- Make banner a separate function with optional distribution banner
- Add a few neat ANSI escape sequences for cls(), clreol(), delline(), etc.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2013-05-21 12:52:06 +02:00
Joachim Nilsson 7e9ac7ba67 Fix indentation and ReST syntax.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2013-05-20 15:32:04 +02:00
Joachim Nilsson e2eaee9620 TODO: Add entry on mimicing Debian SysV init rcS.d, runs once at boot.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2013-05-20 15:25:14 +02:00
Joachim Nilsson b23ce7ab8e Update TODO
More inspiration and courage from the launchd Google Talk video!
Fascinating stuff about replacing init/inetd/cron/watchdogd that
I've been thinking about for ages!

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2013-05-19 23:39:23 +02:00
Joachim Nilsson 53127a7ce6 Update TODO
Move to use ReST syntax, like README, and update to reflect current
status of project.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2013-05-19 19:01:45 +02:00
Joachim Nilsson 011b73ba39 Fix issue with "Formatting of boot text changes in the middle of the boot."
This commit adds a line: "Loading kernel modules ..." before increasing
indentation level of module loading messages.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2013-05-19 19:01:45 +02:00
Mattias Walström 5d04a72a61 Add support for toggling the debug mode at runtime
This commit adds support for -d, --debug option to init, which can
be used to toggle the finit debug mode at runtime.

Signed-off-by: Mattias Walström <lazzer@gmail.com>
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2013-05-19 19:01:44 +02:00
Joachim Nilsson c3b76fdccf Add basic support for runlevels and bugfix FIFO I/O plugins
Like most other init implementations do, when entering runlevel 1, finit
creates the file /etc/nologin to prevent users from logging in during
single-user mode, this file is then removed upon leaving runlevel 1.

Also, bugfix how FIFO I/O plugins are handled in finit.  A FIFO will
need to be reopened by the server side when the client closes the pipe.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2013-05-19 19:01:44 +02:00
Mattias Walström ec95243dad libite: Fix memory leak in dir()
Signed-off-by: Mattias Walström <lazzer@gmail.com>
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2013-05-19 19:01:44 +02:00
Joachim Nilsson ae5d4a0bb2 Add support for user/distribution specific banner at startup.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2013-05-19 19:01:44 +02:00
Joachim Nilsson 0231f858e9 helpers.c: Make system message optional top run_interactive()
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2013-05-19 19:01:44 +02:00
Joachim Nilsson 5d6db9f76f tty.c: Minor cleanup and check global variable before dereferencing.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2013-05-19 19:01:44 +02:00
Mattias Walström 3bcefd2160 Add support for specifying TTYs and console TTY in finit.conf
This commit adds support for specifying TTY and console to be used
for starting a getty to login to the system

Add the following to your finit.conf to use this feature:

    tty ttyS0
    tty ttyUSB0
    console ttyS0

Signed-off-by: Mattias Walström <lazzer@gmail.com>
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2013-05-19 18:45:27 +02:00
Joachim Nilsson 89675403d8 Add support for service restart counter.
This commit adds a statistics counter to the finit svc_t process struct
which is incremented every time a process is restarted by the service
monitor.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2013-05-19 18:00:31 +02:00
Joachim Nilsson f277166354 sig.c: Use watchdogd to reboot system
This patch reorders the shutdown/reboot handler slightly and fixes
a bug in sleep().  It seems the sleep() syscall was interrupted by
receiving lots of SIGCHLD.  Unsurprisingly since we just sent all
processes SIGTERM, but unfortunate since that was too short time
to deliver SIGTERM to watchdogd.

We now call sleep() again, as long as it returns a non-zero value,
until at most two (2) seconds have passed.  During this time we
basically pend for watchdogd to do its job and let the WDT reboot
the system.  If the two second timeout passes we send SIGKILL and
forcibly reboot(RB_AUTOBOOT) the system.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2013-05-19 18:00:31 +02:00
Joachim Nilsson b212babc87 helpers.c: Fix run() argparser, assumed all commands have args. 2013-05-19 18:00:31 +02:00
Joachim Nilsson 6518c2d246 libite: Improve error handling for copyfile() and rsync()
When using the simple rsync() or copyfile() functions of libite some
error codes should not be interpreted as error.  I.e., if a file or
directory already exists when attempting to create it.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2013-05-19 18:00:31 +02:00
Joachim Nilsson c551228079 Makefile: Minor cleanup and only set ROOTDIR if unset already.
The ROOTDIR variable is used for pretty formatting during compilation.
Some users might want to have this display the build from the top of
their tree instead of the finit build tree.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2013-05-19 18:00:31 +02:00
Joachim Nilsson c1198087af TODO: Update with requests for more consoles and runlevel support 2013-05-19 18:00:31 +02:00
Joachim Nilsson 990ccc6d8b Merge pull request #2 from mattiaswal/eglibc
Add support for strlcpy and strlcat
2013-02-19 09:30:22 -08:00
Joachim Nilsson 56a16066b7 Merge pull request #1 from mattiaswal/tty
Add basic support to specify TTYs in configuration
2013-02-19 09:30:06 -08:00
Mattias Walström 407a47dd12 libite: Add strlcat and strlcpy.
These function only exist on uClibc and BSD, so if they
not already defined in string.h, define them here.
2013-01-29 13:29:45 +01:00
Mattias Walström 73b43b4f2b Add missing include <sys/stat.h> 2013-01-29 13:16:21 +01:00
Mattias Walström 5961748b2a Add basic support to specify login TTYs in configuration
This also adds support for monitor /dev for TTYs appering after boot,
USB-to-serial converters for example.

Some limitations: Baudrate (and other settings) is hardcoded for now,
should be read from config file.
2013-01-22 21:17:20 +01:00
Joachim Nilsson a18c5f3441 Update ChangeLog and bump version for release.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2012-10-08 12:05:21 +02:00
Joachim Nilsson 03c47a4020 Only cls() when verbose mode enabled, maybe we should remove it?
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2012-10-08 11:59:56 +02:00
Joachim Nilsson 77b0df3d07 Bugfix: Do not free() static string in new runparts directive
This is a bugfix to 785c21d, which introduced the new runparts
directive in finit.conf

- Do not attempt to free() a static string, use same approach as
  username and hostname.

- Do not overwrite hostname, set the correct variable if runparts
  directive is found in finit.conf

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2012-10-08 11:42:19 +02:00
Joachim Nilsson 7e3465a022 Clear recorded PID of lost service.
Many callbacks check their svc->pid to determine SVC_RELOAD or SVC_START,
they rely on it to be updated.  When a service is lost we must therefore
clear its recorded PID before asking the callback what to do.

Also, swap comparison in debug code for dumping service arguments ...

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2012-10-07 02:00:16 +02:00
Joachim Nilsson 04fd3f7a1b Add __FILE__ to _d() debug to see finit:plugin.c:enabled() ...
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2012-10-06 21:32:26 +02:00
Joachim Nilsson 685618691d Update ChangeLog and bump version for release. 2012-10-06 18:07:39 +02:00
Joachim Nilsson f29d2733c7 Fix incorrect use of variable arguments in run_parts() and simplify code
The run_parts() implementation used variable arguments in a bad way,
resulting in it not working properly.  Replaced va_*() code with a
simple cmd argument that's passed to each script called.

Also, the opendir()/readdir() code has been replaced with scandir()
using regular alphasort(). This simplifies the code somewhat as well.

Otherwise, minor cleanups.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2012-10-06 15:45:42 +02:00
Joachim Nilsson af59174e49 Prevent endless restart of non-existing services and support start-stop scripts
Sometimes people type in the wrong path to a service directive in
finit.conf, or the executable isn't installed.  This commit makes
sure to check if the command exists before attempting to start it.
This also means that we now require service commands to start with
/ to indicate an absolute path.  We used to search the PATH for a
suitable executable, using execvp(), but that's rather insecure as
well, so we now use only execv().

Also, added support for adding "start" or "stop" to entries found
in /etc/finit.d starting with SNNname, or KNNname, where NN is a
number.  This makes it possible to simply import sysvinit style
start scripts from /etc/rcS.d and /etc/rcN.d/.

The alsa-utils plugin also had some minor fixes, added -g option
to ignore non-existing soundcards and fixed cut-paste bug on the
_d() debug messages.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2012-10-06 13:56:26 +02:00
Joachim Nilsson 785c21d27b Support for overriding built-in default FINIT_RCSD in finit.conf
This commit adds support for the "runparts <DIR>" directive to
finit.conf.  Enabling the user to override the built-in default,
which by default is /etc/finit.d.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2012-10-05 18:50:21 +02:00
Joachim Nilsson 40c7a44d4f Skip . and .. in plugin loader and trigger error on failed plugin load.
Fix from field testing.  Need to skip "." and ".." directory entries
when loading plugins from /lib/finit/plugins.  Also, trigger an error
when a required plugin fails to load.  We need to print to console
since syslogd has not started yet.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2012-10-04 17:22:40 +02:00
Joachim Nilsson cbb50937cd Update ChangeLog and bump version.
New release, 1.5! :)

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2012-10-03 23:30:23 +02:00
Joachim Nilsson 83a4bf7947 Add dependency resolver for plugins.
This has been something I wanted to avoid, but then I stumbled so hard
on it myself I simply had to add it.  With this commit finit actually
comes of age -- it's now possible to do anything a modern init can --
only faster! :-)

Included in this commit is the OpenBSD version of sys/queue.h, which
unline all versions of the same file on Linux has the _FOREACH_SAFE
macros for iterating over a linked list.

The plugins are now in a TAILQ, loaded in alphabetic order and, unless
the dependency resolver says otherwise, added last in the queue.  So,
naming your plugins according to standard sysvinit rules: S01, S02,
etc. takes care of the most basic dependency resolution.  When that is
not sufficient, simply add a line ".depends = { "other_plugin",
"another_plugin" }," to your plugin_t definition.  Be careful though
for circular dependencies, we don't check for those.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2012-10-03 23:20:34 +02:00
Joachim Nilsson 0d7d5a9820 Setup standard FHS 2.3 structure in /var
This was missing from the 1.4 release due to it being hidden in one
of my private plugins. Sorry!

Also, add another log macro. Warnings are quite useful things to have.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2012-10-03 11:44:33 +02:00
Joachim Nilsson 65c9e7ebc6 Fix I/O plugin watcher, load plugins earlier to enable a new early hook!
Restructure start by calling the plugin loader earlier. This makes it
possible to run hooks even earlier.  This also adds a new hook:
HOOK_ROOTFS_UP which runs as soon as the system root (/) is available.

Another very notable change is the slow refactor of helpers.c into a finit
helper library called libite.so (-lite). This is a light-weight

Also, lots of misc. fixes all over the place. Signal handling still really
needs to be looked into once more!

Makefile:
        Add dependency handling for parallell build
        Add libite library

ChangeLog:
        Update with new 1.4 release. There is a lot of fixes!

libite/:
        Collection of utility functions and C library extensions for
        finit & its plugins

reboot.c:
        New reboot tool. Simply sends SIGINT to PID 1

finit.h:
        Cleanup old LISTEN_INITCTL define, code is in an optional plugin now

finit.c:
        Let mdev/udev run *after* cls()
        Add useful debug statement for /proc/cmdline
        Earlier plugin load => new early hook point
        Show OK/FAIL for total plugin load, not for each plugin => speedup

helpers.h:
        Rename syslog macros to prevent common name clashes (DEBUG/ERROR)
        Add __FILE__ to _e(), _d() and _pe() macros

helpers.c:
        In ifconfig() the addr and mask arguments are now optional
        The copyfile() has been moved to libite.so
        Temporarily remove const directive from some functions to build
        Use DFLSIG() macro in run_getty() to simplify code

plugin.h:
        Add new HOOK_ROOTFS_UP hook

plugin.c:
        Fix init_plugins() to actually register the plugin's I/O fd
        Skip verbose listing of all plugins in plugin_load_all()

svc.c:
        svc_start(): Dito

plugins/Makefile:
        Inherit CFLAGS and LDFLAGS, but make sure to filter out -rdynamic
        from LDFLAGS, it's used by the daemon, only

plugins/initctl.c:
        New includes after helpers.h refactor

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2012-10-02 08:25:50 +02:00
Joachim Nilsson c002b5301f plugins/hwclock: Use short-form -s/-w -u to work with BusyBox hwclock as well.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2012-10-02 06:39:26 +02:00
Joachim Nilsson 3f1c2f6211 Plugin loader and registration fixes
- Use RTLD_GLOBAL flag to tell dynamic loader to load dependent .so
  files as well.  Also lets other plugins use globally scoped symbols.

- Check for plugin hooks as well before dismissing plugin as unused.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2012-10-02 06:39:26 +02:00
Joachim Nilsson 5116cd66ef Greatly simplify svc hook for external plugins
This commit removes a lot of unnecessary overhead for handling external
service plugins.  Instead of traversing the plugin array every time a
service callback should run we set the plugin callback in the svc_t when
the plugin is registered.

Also, make sure to check for norespawn/SIGSTOP in svc_reload() as well.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2012-10-02 06:39:26 +02:00
Joachim Nilsson f55f68d032 Cleanup and refactor of public plugin API
Improve upon API names, both internal and external, to make it clearer
where methods are located and clarify responsibility.

Add new Makefile target "dev" to create untagged development snapshots.

Bump version for upcoming release.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2012-10-02 06:39:19 +02:00
Joachim Nilsson 5e99b5e735 Minor API change.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2012-09-29 15:13:13 +02:00
Joachim Nilsson d26852e07a README: Further cleanup
Remove prefix= from list of overridden environment variables in example.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2012-09-28 18:00:49 +02:00
Joachim Nilsson a90a7c04e4 README: Further updates, clarification and additions on, e.g., running finit.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2012-09-28 17:56:26 +02:00
Joachim Nilsson 14a1fb9cde Create /etc/finit.d at install and update README with v1.3 changes.
Updates to README include changed environment variables and a
clarification of why there is no default /etc/finit.conf after make
install.

Also, the /etc/finit.d directory is now created, as expected, by
make install.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2012-09-28 17:26:31 +02:00
114 changed files with 12873 additions and 2191 deletions
+31 -2
View File
@@ -1,6 +1,35 @@
*~
*.o *.o
.*.d
*.so *.so
*.gz *.gz
*.map *.map
finit configure
Makefile
Makefile.in
/.deps/*
/.libs/*
/finit
/initctl
/reboot
/config.h
/config.mk
/GPATH
/GRTAGS
/GSYMS
/GTAGS
/autom4te.cache/*
/aclocal.m4
/ar-lib
/compile
/config.guess
/config.h.in
/config.log
/config.status
/config.sub
/depcomp
/install-sh
/libtool
/ltmain.sh
/missing
/stamp-h1
View File
+56
View File
@@ -0,0 +1,56 @@
# Travis CI integration -- https://travis-ci.org/troglobit/finit
# Defaults to GNU GCC and autotools: ./configure && make && make test
language: c
# Use docker for quicker builds, it now allows https://docs.travis-ci.com/user/apt/
sudo: false
# Use non-docker builds atm. to install libuEv and libite from source
#sudo: true
# Test build with both GCC and Clang (LLVM)
compiler:
- gcc
- clang
env:
global:
# The next declaration is the encrypted COVERITY_SCAN_TOKEN, created
# via the "travis encrypt" command using the project repo's public key
- secure: "eOiuHs02lG2Uv146K9dMqucGTWUJFEhpz1oAtwe+kPrRXsXWc20hYMO+DSpMgD05vSvNeQA6p7h7LdRFQ+/g/Obj27TsOE+RKkUvRAtdwzxnKVyii9C/nmML8cFw7rIA0VS8O9mAkVYeyDxNDupBp3e9DPCibhKPvqCvioTnyy4="
addons:
apt:
packages:
- tree
coverity_scan:
project:
name: "troglobit/finit"
description: "finit | Fast & Extensible init for Linux"
notification_email: troglobit@gmail.com
build_command_prepend: "./autogen.sh && PKG_CONFIG_PATH=/tmp/lib/pkgconfig ./configure --prefix=/tmp"
build_command: "make"
branch_pattern: dev
install:
- 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.5.2.tar.xz
- tar xf libite-1.8.2.tar.xz
- (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
script:
- ./autogen.sh
- PKG_CONFIG_PATH=/tmp/lib/pkgconfig ./configure --prefix=/tmp
- cat config.log
- make clean
- make -j5 V=1
- make install-strip
- tree /tmp
- ldd /tmp/sbin/finit
- size /tmp/sbin/finit
- size /tmp/sbin/initctl
- size /tmp/sbin/reboot
- LD_LIBRARY_PATH=/tmp/lib /tmp/sbin/initctl -h
-78
View File
@@ -1,78 +0,0 @@
1.3 (20120928)
- Cleanup public plugin API a bit and add new pid/pidfile funcs
- Add plugin hook to end of service startup
- Remove finit.h from svc.h, plugins should not need this.
- Move utility macros etc. to helpers.h
- Make finit.h daemon internal, only
- Move defines of FIFO, conf and rcS.d to Makefile => correct paths
- Add support for installing required headers in system include dir
- Better support for distributions and packagers with install-exec,
install-data, and install-dev targets in Makefile. Useful if you
want to call targets with different $DESTDIR!
- Makefile fixes for installation, paths encoded wrong
- Strip binaries + .so files, support for $(CROSS) toolchain strip
- Default install is now to /sbin/finit and /usr/
- Note change in $PLUGIN_DIR environemnt variable to $plugindir
1.2 (20120927)
- Fix installation paths encoded in finit binary
- Update README with section on building and enviroment variables
1.1 (20120927)
- Build fixes for ARM eabi/uClibc
- Rename signal.[ch]-->sig.[ch] to avoid name clash w/ system headers
1.0 (20120926)
- New plugin based system for all odd extensions
- New service monitor that restarts services if they die
- New maintainer at GitHub http://github.com/troglobit/finit
- Add standard LICENSE and AUTHORS files
- New focus: embedded systems and small headless servers
0.6 (20100614)
- don't start consolekit manually, dbus starts it (rtp)
- unmount all filesystems before rebooting
- disable USE_VAR_RUN_RESOLVCONF for Mandriva
- unset terminal type in Mandriva before running X
- remove extra sleep in finit-alt before calling services.sh (caio)
0.5 (20080821)
- add option to start dbus and consolekit before the X server
- finit-alt listens to /dev/initctl to work with reboot(8) (smurfy)
- write runlevel to utmp, needed by Printerdrake (Pascal Terjan)
- fix ownership of /var/run/utmp (reported by Pascal Terjan)
- remove obsolete code to load AGP drivers
- conditional build of /etc/resolveconf/run support
- add support to /var/run/resolvconf in Mandriva (blino)
O.4 (20080516)
- default username for finit-alt configurable in Makefile
- create loopback device node in finit-alt (for squashfs)
- add option to use built-in run-parts instead of /bin/run-parts
- ignore signal instead of setting to an empty handler (Metalshark)
- handle pam_console permissions in finit-alt for Mandriva
- add services.sh example and nash-hotplug patch for Mandriva
- mount /proc/bus/usb in Mandriva
- add runtime debug to finit-alt if finit_debug parameter is specified
- read configuration from /etc/finit.conf
- run getty with openvt on the virtual terminal
0.3 (20080223)
- Change poweroff method to reboot(RB_POWER_OFF) (Metalshark)
- Remove duplicate unionctl() reimplementation error
- Fix string termination in path creation
- Mount /var/lock and /var/run as tmpfs
0.2 (20080219)
- replace system("touch") with touch() in finit-mod (Metalshark)
- disable NO_HCTOSYS by default to match stock Eeepc kernel
- drop system("rm -f") to clean /tmp, its a fresh mounted tmpfs
- write ACPI sleep state to /sys/power/state instead of
/proc/acpi/sleep (Metalshark)
- use direct calls to set loopback instead of system("ifconfig")
- replace system("cat") and system("dd") with C implementation
- moved finit-mod and finit-alt helpers to helpers.c
- replace system("echo;cat") to draw shutdown splash with C calls
0.1 (20080214)
- initial release
+551
View File
@@ -0,0 +1,551 @@
Change Log
==========
All relevant changes are documented in this file.
[3.0][UNRELEASED] - 2016-XX-YY
------------------------------
### Changes
* Manage service states based on user defined conditions
* Manage dependencies between services, w/ conditions (pidfile plugin)
* Manage service dependenceis on network events (netlink plugin)
* Support for dynamically reloading Finit configuration at runtime
* Refactor to use GNU configure and build system
* New hooks for for detecting lost and started services (lost plugin)
* External libraries, libuEv and libite, now build requirements
* Early logging support to `/dev/kmsg` instead of console
* Support for redirecting stdout/stderr of services to syslog
* Support for managing resource limits for Finit and its processes
* Add optional built-in inetd services: echo server, chargen, etc.
* Add simple built-in getty
* Greatly improved accounting support, both UTMP and WTMP fixes+features
* Improved udev support, on non-embedded systems
* Improvide shutdown and file-system unmount support (Debian)
* Added `--enable-emergency-shell` (configure) fallback debug mode
* Support SysV init `/etc/rc.local`
* Inetd protection against UDP looping attacks
* Support systems with `/run` instead of `/var/run` (bootmisc plugin)
* Adopted BusyBox init signals for halt/reboot/poweroff
* SysV init compat support for reboot (setenv)
* Compat support for musl libc
* Add OpenRC-like support for sysctl.d/*.conf
* Add support for Debian/BusyBox `/etc/network/interfaces`
* Add support for running fsck on file systems in `/etc/fstab`
* Added example configs + HowTos for Debian (Jessie) and Alpine Linux
[2.4][] - 2015-12-04
--------------------
Bug fix release.
### Changes
* Add support for status/show service by `name:id`
* Enforce terse mode after boot, if verbose mode is disabled
* Reenable verbose mode at reboot, if disabled at boot
* Update section mentioning BusyBox getty
* Update debugging documentation
* Allow debug to override terse mode
* Revert confusing change in service state introduced in [v2.3][2.3].
As of [v2.4][2.4] services are listed as "halted" and "stopped", when
they have been halted due to a runlevel changed or stopped by the
user, respectively.
### Fixes
* Fix system freeze at reconfiguration. Changed services that
all support `SIGHUP` caused a freeze due to Finit waiting for
them to stop.
* Make sure to start and/or `SIGHUP` services after reconfiguration
when there was no services to stop.
[2.3][] - 2015-11-28
--------------------
Bug fix release.
### Changes
* Add support for stop/start/restart/reload service by `name:id`
* Refactor service status listed in `initctl show`, show actual status
### Fixes
* Remove bootstrap-only tasks/services when leaving runlevel 'S'
* Fix reference counting issue with already stopped and removed services
when the user performs `initctl reload` to change system configuration
* Revert semantic change in behavior of `initctl restart`: users expect
service to be stopped/started, not reloaded with `SIGHUP` even if the
service supports it
* Fix `NULL` pointer dereference causing kernel panic when user calls
`initctl reload` after change of system configuration
* Fix column alignment in output of `initctl show` for services not in
current runlevel
[2.2][] - 2015-11-23
--------------------
Lots of fixes to handle static builds, but also fixes for dynamic event
handling and reconfiguration at runtime.
### Changes
* Upgrade to libuEv v1.2.4, to handle static builds
* Upgrade to libite (LITE) v1.2.0, to handle static builds
* Clarify how to select different plugins with the configure script
* Improve urandom plugin for embedded systems w/o random seed
* Add `--debug` flag to `initctl`
* The runlevels listed for services in `initctl show` now hightlight the
active runlevel.
* Clarify in the README and in `initctl help` that the GW event to
listen for in service declarations is `GW:UP`
### Fixes
* Build fixes for `configure --disable-inetd`
* Fixed issue #14: Improved support for static Finit builds
* Misc. fixes to silence warnings when building a static Finit
* Default to register services as `SIGHUP`'able, regression in v2.0
* Call `HOOK_SVC_RECONF` only when all processes have been stopped
* On reload/reconf we must wait for all services to stop first
* Only trigger on events that matches the service's specification,
fix by Tobias Waldekranz
[2.1][] - 2015-10-16
--------------------
### Changes
* Add hook point for fstab mount failure
* Set hostname on dynamic reload
* Upgrade to libite v1.1.1
### Fixes
* Fix service callback coredump checks and simplify callback exit
* Do not use `-Os` use `-O2` as default optimization level. Many cross
compiler toolchains are known to have problems with `-Os`
* Do not allow build VERSION to be overloaded by an environment variable
* Fix too small MAX arguments and too few argments in `svc_t` for
reading currently running services with `initctl show`
* Unblock blocked signals after forking off a child
[2.0][] - 2015-09-20
--------------------
Support for multiple instances and event based services, as well as the
introduction of an `initctl` tool.
**Note:** Incompatible change to syntax for custom `inetd` services,
c.f. Finit v[1.12][].
### Changes
* The most notable change is the support for multiple instances. A must
have when running multiple DHCP clients, OpenVPN tunnels, or anything
that means using the same command only with different arguments. Now
simply add a `:ID` after the `service` keyword, where `ID` is a unique
instance number for that service.
service :1 [2345] /sbin/httpd -f -h /http -p 80 -- Web server
service :2 [2345] /sbin/httpd -f -h /http -p 8080 -- Old web server
* Another noteworthy new feature is support for starting/stopping
services on Netlink events:
service :1 [2345] <!IFUP:eth0,GW> /sbin/dropbear -R -F -p 22 -- SSH daemon
Here the first instance `:1` of the SSH daemon is declared to run in
runlevels 2-5, but only if eth0 `IFUP:eth0` is up and a gateway `GW`
is set. When the configuration changes, a new gateway is set, or if
somehow a new `IFUP` event for eth0 is received, then dropbear is not
SIGHUP'ed, but instead stop-started `<!>`. The latter trick applies
to all services, even those that do not define any events.
* Support for reloading `*.conf` files in `/etc/finit.d/` on SIGHUP.
All `task`, `service` and `run` statements can be used in these .conf
files. Use the `telinit q` command, `initctl reload` or simply send
`SIGHUP` to PID 1 to reload them. Finit automatically does reload of
these `*.conf` files when changing runlevel.
* Support for a modern `initctl` tool which can stop/start/reload and
list status of all system services. Also, the old client tool used
to change runlevel is now also available as a symlink: `telinit`.
initctl [-v] <status|stop|start|reload|restart> [JOB]
* Add concept of "jobs". This is a unique identifier, composed of a
service and instance number, `SVC:ID`
initctl <stop|start|reload|restart> JOB
* Support for *deny filters* in `inetd` services.
inetd service/proto[@iface,!iface,...] </path/to/cmd | internal[.service]>
Internal services on a custom port must use the `internal.service`
syntax so Finit can properly bind the inetd service to the correct
plugin. Here follows a few examples:
inetd time/udp wait [2345] internal -- UNIX rdate service
inetd time/tcp nowait [2345] internal -- UNIX rdate service
inetd 3737/tcp nowait [2345] internal.time -- UNIX rdate service
inetd telnet/tcp@*,!eth1,!eth0, nowait [2345] /sbin/telnetd -i -F -- Telnet service
inetd 2323/tcp@eth1,eth2,eth0 nowait [2345] /sbin/telnetd -i -F -- Telnet service
inetd 222/tcp@eth0 nowait [2345] /sbin/dropbear -i -R -F -- SSH service
inetd ssh/tcp@*,!eth0 nowait [2345] /sbin/dropbear -i -R -F -- SSH service
Access to telnet on port `2323` is only possible from interfaces
`eth0`, `eth1` and `eth2`. The standard telnet port (`23`) is
available from all other interfaces, but also `eth2`. The `*`
notation used in the ssh stanza means *any* interface, however, here
`eth0` is not allowed.
**NOTE:** This change breaks syntax compatibility with Finit v[1.12].
* Support for a more user-friendly configure script rather than editing
the top Makefile, or setting environment variables at build time.
* Support for building Finit statically, no external libraries. This
unfortunately means that some plugins cannot be built, at all.
Big thanks goes to James Mills for all help testing this out!
* Support for disabling the built-in inetd server with `configure`.
* Support for two new hook points: `HOOK_SVC_RECONF` and
`HOOK_RUNLEVEL_CHANGE`. See the source for the exact location.
* The `include <FILE>` option now needs an absolute path to `FILE`.
### Fixes
* Rename `patches/` to `contrib/` to simplify integration in 3rd party
build systems.
* Fix for unwanted zombies ... when receiving SIGCHLD we must reap *all*
children. We only receive one signal, but multiple processes may have
exited and need to be collected.
[1.12][] - 2015-03-04
---------------------
The inetd release.
### Changes
* Add support for built-in inetd super server -- launch services on
demand. Supports filtering per interface and custom Inet ports.
* Upgrade to [libuEv] v1.1.0 to better handle error conditions.
* Allow mixed case config directives in `finit.conf`
* Add support for RFC 868 (rdate) time plugin, start as inetd service.
* Load plugins before parsing `finit.conf`, this makes it possible to
extend finit even with configuration commands. E.g., the `time.so`
plugin must be loaded for the `inetd time/tcp internal` service to be
accepted when parsing `finit.conf`.
* Slight change in TTY fallback behavior, if no TTY is listed in the
system `finit.conf` first inspect the `console` setting and only if
that too is unset fall back to `/bin/sh`
* When falling back to the `console` TTY or `/bin/sh`, finit now marks
this fallback as console. Should improve usability in some use cases.
### Fixes
* Revert "Use vfork() instead of fork() before exec()" from v1.11. It
turned out to not work so well after all. For instance, launching
TTYs in a background process completely blocked inetd services from
even starting up listening sockets ... proper fork seems to work fine
though. This is the casue for *yanking* the [1.11] release, below.
* Trap segfaults caused by external plugins/callbacks in a sub-process.
This prevents a single programming mistake in by a 3rd party developer
from taking down the entire system.
* Fix Coverity CID 56281: dlopen() resource leak by storing the pointer.
For the time being we do not support unloading plugins.
* Set hostname early, so bootstrap processes like syslog can use it.
* Only restart *lost daemons* when recovering from a SIGSTOP/norespawn.
[1.11][] - 2015-01-24 [YANKED]
------------------------------
The [libuEv] release.
**Note:** This release has been *yanked* from distribution due to a
regression in launching background processes and TTY's. Fixed in
Finit v[1.12].
### Changes
* Now using the asynchronous libuEv library for handling all events:
signals, timers and listening to sockets or file descriptors.
* Rename NEWS.md --> CHANGELOG.md, with symlinks for `make install`
* Attempt to align with http://keepachangelog.com/ for this file.
* Travis CI now only invokes Coverity Scan from the 'dev' branch. This
means that all development, except documentation updates, must go into
that branch.
### Fixes
* Fix bug with finit dying when no `tty` is defined in `finit.conf`, now
even the fallback shell has control over its TTY, see fix in GIT
commit [dea3ae8] for this.
[1.10][] - 2014-11-27
---------------------
Major bug fix release.
### Changes
* Project now relies on static code analysis from Coverity, so this
release contains many serious bug fixes.
* Convert to use Markdown for README, NEWS and TODO.
* Serious update to README and slight pruning of finished TODO items.
### Fixes
* Fix serious file descriptor and memory leaks in the following
functions. In particular the leaks in `run_interactive()` are very
serious since that function is called every time a service is started
and/or restarted! For details, see the GIT log:
* `helpers.c:run()`
* `helpers.c:run_interactive()`
* `helpers.c:set_hostname()`
* `helpers.c:procname_kill()`
* `svc.c:svc_start()`: Fix swapped arguments to dup2() and add close(fd)
to prevent descriptor leak.
* `svc.c:svc_start()`: Fix out of bounds write to local stack variable,
wrote off-by-one outside array.
* Several added checks for return values to `mknod()`, `mkdir()`,
`remove()`, etc.
[1.9][] - 2014-04-21
--------------------
### Changes
* Add support for an include directive to `.conf` files
* Fallback to `/bin/sh` if user forgets tty setting
* Initial support for restarting lost services during `norespwan`
### Fixes
* Bug fixes, code cleanup
* Handle `SIGHUP` from service callback properly when switching runlevel
* Misc. major (memleak) and minor fixes and additions to `libite/lite.h`
[1.8][] - 2013-06-07
--------------------
### Changes
* Support for runlevels, with a bootstrap runlevel 'S'
* Support for saving previous and current runlevel to UTMP
* Support for new `finit.conf` commands: run, task, and runlevel
* Support for tty and console commands in `finit.conf`, like services
but for launching multiple getty logins
* New tty plugin to monitor TTYs coming and going, like USB TTYs
### Fixes
* Bugfixes to libite
[1.7][] - 2012-10-08
--------------------
### Changes
* Show `__FILE__` in `_d()` debug messages, useful for plugins with
similarily named callbacks. Also, only in debug mode anyway
* Make sure to cleanup recorded PID when a service is lost. Required by
service plugins for their callbacks to work.
* Only clear screen when in verbose mode. Maybe this should be removed
altogether?
### Fixes
* Bugfix: Do not `free()` static string in `finit.conf` parser
[1.6][] - 2012-10-06
--------------------
### Changes
* Skip `.` and `..` in plugin loader and display error when failing to
load plugins
* Support for overriding `/etc/finit.d` with `runparts DIR` in
`finit.conf`
* Revoke support for starting services not starting with a slash.
* Prevent endless restart of non-existing services in `finit.conf`
* Support for sysvinit style startstop scripts in `/etc/finit.d`
### Fixes
* Minor fix to alsa-utils plugin to silence on non-existing cards
[1.5][] - 2012-10-03
--------------------
### Changes
* Use bootmisc plugin to setup standard FHS 2.3 structure in `/var`
* Added `FLOG_WARN()` syslog macro, for plugins
* Add plugin dependency resolver. Checks `plugin_t` for `.depends`
[1.4][] - 2012-10-02
--------------------
### Changes
* Start refactoring helpers.c into a libite.so (-lite). This means
other user space applications/daemons can make use of the neat toolbox
available in finit
* Use short-form -s/-w -u to work with BusyBox hwclock as well
* Use RTLD_GLOBAL flag to tell dynamic loader to load dependent .so
files as well. Lets other plugins use global symbols.
* Greatly simplify svc hook for external plugins and cleanup plugin API.
* And more ... see the GIT log for more details.
### Fixes
* Fix I/O plugin watcher and load plugins earlier for a new hook
[1.3][] - 2012-09-28
--------------------
### Changes
* Cleanup public plugin API a bit and add new pid/pidfile funcs
* Add plugin hook to end of service startup
* Remove finit.h from svc.h, plugins should not need this.
* Move utility macros etc. to helpers.h
* Make `finit.h` daemon internal, only
* Move defines of FIFO, conf and rcS.d to Makefile => correct paths
* Add support for installing required headers in system include dir
* Better support for distributions and packagers with install-exec,
install-data, and install-dev targets in Makefile. Useful if you want
to call targets with different `$DESTDIR`!
* Makefile fixes for installation, paths encoded wrong
* Strip binaries + .so files, support for `$(CROSS)` toolchain strip
* Default install is now to `/sbin/finit` and `/usr/`
* Note change in `$PLUGIN_DIR` environemnt variable to `$plugindir`
[1.2][] - 2012-09-27
--------------------
### Changes
* Update README with section on building and enviroment variables
### Fixes
* Fix installation paths encoded in finit binary
[1.1][] - 2012-09-27
--------------------
### Changes
* Rename signal.[ch]-->sig.[ch] to avoid name clash w/ system headers
### Fixes
* Build fixes for ARM eabi/uClibc
[1.0][] - 2012-09-26
--------------------
### Changes
* New plugin based system for all odd extensions
* New service monitor that restarts services if they die
* New maintainer at GitHub http://github.com/troglobit/finit
* Add standard LICENSE and AUTHORS files
* New focus: embedded systems and small headless servers
[0.6][] - 2010-06-14
--------------------
* Don't start consolekit manually, dbus starts it (rtp)
* Unmount all filesystems before rebooting
* Disable `USE_VAR_RUN_RESOLVCONF` for Mandriva
* Unset terminal type in Mandriva before running X
* Remove extra sleep in finit-alt before calling services.sh (caio)
[0.5][] - 2008-08-21
--------------------
* Add option to start dbus and consolekit before the X server
* finit-alt listens to `/dev/initctl` to work with `reboot(8)` (smurfy)
* Write runlevel to utmp, needed by Printerdrake (Pascal Terjan)
* Fix ownership of `/var/run/utmp` (reported by Pascal Terjan)
* Remove obsolete code to load AGP drivers
* Conditional build of `/etc/resolveconf/run` support
* Add support to `/var/run/resolvconf` in Mandriva (blino)
[0.4][] - 2008-05-16
--------------------
* Default username for finit-alt configurable in Makefile
* Create loopback device node in finit-alt (for squashfs)
* Add option to use built-in run-parts instead of `/bin/run-parts`
* Ignore signal instead of setting to an empty handler (Metalshark)
* Handle pam_console permissions in finit-alt for Mandriva
* Add services.sh example and nash-hotplug patch for Mandriva
* Mount `/proc/bus/usb` in Mandriva
* Add runtime debug to finit-alt if finit_debug parameter is specified
* Read configuration from `/etc/finit.conf`
* Run getty with openvt on the virtual terminal
[0.3][] - 2008-02-23
--------------------
* Change poweroff method to `reboot(RB_POWER_OFF)` (Metalshark)
* Remove duplicate `unionctl()` reimplementation error
* Fix string termination in path creation
* Mount `/var/lock` and `/var/run` as tmpfs
[0.2][] - 2008-02-19
--------------------
* Replace `system("touch")` with `touch()` in finit-mod (Metalshark)
* Disable `NO_HCTOSYS` by default to match stock Eeepc kernel
* Drop `system("rm -f")` to clean `/tmp`, its a fresh mounted tmpfs
* Write ACPI sleep state to `/sys/power/state` instead of
`/proc/acpi/sleep` (Metalshark)
* Use direct calls to set loopback instead of `system("ifconfig")`
* Replace `system("cat")` and `system("dd")` with C implementation
* Moved finit-mod and finit-alt helpers to `helpers.c`
* Replace `system("echo;cat")` to draw shutdown splash with C calls
0.1 - 2008-02-14
----------------
* Initial release
[UNRELEASED]: https://github.com/troglobit/finit/compare/2.4...HEAD
[2.4]: https://github.com/troglobit/finit/compare/2.3...2.4
[2.3]: https://github.com/troglobit/finit/compare/2.2...2.3
[2.2]: https://github.com/troglobit/finit/compare/2.1...2.2
[2.1]: https://github.com/troglobit/finit/compare/2.0...2.1
[2.0]: https://github.com/troglobit/finit/compare/1.12...2.0
[1.12]: https://github.com/troglobit/finit/compare/1.11...1.12
[1.11]: https://github.com/troglobit/finit/compare/1.10...1.11
[1.10]: https://github.com/troglobit/finit/compare/1.9...1.10
[1.9]: https://github.com/troglobit/finit/compare/1.8...1.9
[1.8]: https://github.com/troglobit/finit/compare/1.7...1.8
[1.7]: https://github.com/troglobit/finit/compare/1.6...1.7
[1.6]: https://github.com/troglobit/finit/compare/1.5...1.6
[1.5]: https://github.com/troglobit/finit/compare/1.4...1.5
[1.4]: https://github.com/troglobit/finit/compare/1.3...1.4
[1.3]: https://github.com/troglobit/finit/compare/1.2...1.3
[1.2]: https://github.com/troglobit/finit/compare/1.1...1.2
[1.1]: https://github.com/troglobit/finit/compare/1.0...1.1
[1.0]: https://github.com/troglobit/finit/compare/0.9...1.0
[0.9]: https://github.com/troglobit/finit/compare/0.8...0.9
[0.8]: https://github.com/troglobit/finit/compare/0.7...0.8
[0.7]: https://github.com/troglobit/finit/compare/0.6...0.7
[0.6]: https://github.com/troglobit/finit/compare/0.5...0.6
[0.5]: https://github.com/troglobit/finit/compare/0.4...0.5
[0.4]: https://github.com/troglobit/finit/compare/0.3...0.4
[0.3]: https://github.com/troglobit/finit/compare/0.2...0.3
[0.2]: https://github.com/troglobit/finit/compare/0.1...0.2
[libuEv]: https://github.com/troglobit/libuev
[dea3ae8]: https://github.com/troglobit/finit/commit/dea3ae8
<!--
-- Local Variables:
-- mode: markdown
-- End:
-->
+1 -1
View File
@@ -1,5 +1,5 @@
Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com> Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
Copyright (c) 2008-2012 Joachim Nilsson <troglobit@gmail.com> Copyright (c) 2008-2014 Joachim Nilsson <troglobit@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
-149
View File
@@ -1,149 +0,0 @@
# Finit - Extremely fast /sbin/init replacement w/ I/O, hook & service plugins
#
# Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
# Copyright (c) 2008-2012 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.
.PHONY: all install clean distclean dist \
install-exec install-data install-dev \
uninstall-exec uninstall-data uninstall-dev
# Top directory for building complete system, fall back to this directory
ROOTDIR ?= $(shell pwd)
#VERSION ?= $(shell git tag -l | tail -1)
VERSION ?= 1.3
EXEC = finit
PKG = $(EXEC)-$(VERSION)
ARCHIVE = $(PKG).tar.xz
HEADERS = plugin.h svc.h helpers.h
DISTFILES = LICENSE README ChangeLog finit.conf services
OBJS = finit.o conf.o helpers.o sig.o svc.o plugin.o
OBJS += strlcpy.o
SRCS = $(OBJS:.o=.c)
DEPS = $(addprefix .,$(SRCS:.c=.d))
# Installation paths, always prepended with DESTDIR if set
prefix ?= /usr
sysconfdir ?= /etc
sbindir ?= /sbin
plugindir ?= /lib/finit/plugins
incdir = $(prefix)/include/finit
datadir = $(prefix)/share/doc/finit
mandir = $(prefix)/share/man/man8
# The initctl FIFO, should probably be in /run, not /dev
FINIT_FIFO ?= /dev/initctl
FINIT_CONF ?= $(sysconfdir)/finit.conf
FINIT_RCSD ?= $(sysconfdir)/finit.d
CFLAGS += -W -Wall -Werror -Os
# Disable annoying gcc warning for "warn_unused_result", see GIT 37af997
CPPFLAGS += -U_FORTIFY_SOURCE
CPPFLAGS += -D_XOPEN_SOURCE=600 -D_BSD_SOURCE -D_GNU_SOURCE
CPPFLAGS += -DVERSION=\"$(VERSION)\" -DWHOAMI=\"`whoami`@`hostname`\"
CPPFLAGS += -DFINIT_FIFO=\"$(FINIT_FIFO)\" -DFINIT_CONF=\"$(FINIT_CONF)\"
CPPFLAGS += -DFINIT_RCSD=\"$(FINIT_RCSD)\" -DPLUGIN_PATH=\"$(plugindir)\"
LDFLAGS += -rdynamic
LDLIBS += -ldl
include common.mk
export plugindir ROOTDIR CPPFLAGS
all: Makefile $(EXEC)
$(MAKE) -C plugins $@
$(OBJS): Makefile
$(EXEC): $(OBJS)
install-exec: all
@$(INSTALL) -d $(DESTDIR)$(sysconfdir)
@$(INSTALL) -d $(DESTDIR)$(sbindir)
@for file in $(EXEC); do \
printf " INSTALL $(DESTDIR)$(sbindir)/$$file\n"; \
$(STRIPINST) $$file $(DESTDIR)$(sbindir)/$$file; \
done
$(MAKE) -C plugins install
install-data:
@$(INSTALL) -d $(DESTDIR)$(datadir)
@$(INSTALL) -d $(DESTDIR)$(mandir)
@for file in $(DISTFILES); do \
printf " INSTALL $(DESTDIR)$(datadir)/$$file\n"; \
$(INSTALL) -m 0644 $$file $(DESTDIR)$(datadir)/$$file; \
done
install-dev:
@$(INSTALL) -d $(DESTDIR)$(incdir)
@for file in $(HEADERS); do \
printf " INSTALL $(DESTDIR)$(incdir)/$$file\n"; \
$(INSTALL) -m 0644 $$file $(DESTDIR)$(incdir)/$$file; \
done
install: install-exec install-data install-dev
uninstall-exec:
-@for file in $(EXEC); do \
printf " REMOVE $(DESTDIR)$(sbindir)/$$file\n"; \
rm $(DESTDIR)$(sbindir)/$$file 2>/dev/null; \
done
-@rmdir $(DESTDIR)$(sbindir) 2>/dev/null
-@rmdir $(DESTDIR)$(sysconfdir) 2>/dev/null
$(MAKE) -C plugins uninstall
uninstall-data:
@for file in $(DISTFILES); do \
printf " REMOVE $(DESTDIR)$(datadir)/$$file\n"; \
rm $(DESTDIR)$(datadir)/$$file 2>/dev/null; \
done
-@rmdir $(DESTDIR)$(mandir)
-@rmdir $(DESTDIR)$(datadir)
uninstall-dev:
-@for file in $(HEADERS); do \
printf " REMOVE $(DESTDIR)$(incdir)/$$file\n"; \
rm $(DESTDIR)$(incdir)/$$file 2>/dev/null; \
done
-@rmdir $(DESTDIR)$(incdir)
uninstall: uninstall-exec uninstall-data uninstall-dev
clean:
-@$(RM) $(OBJS) $(DEPS) $(EXEC)
$(MAKE) -C plugins $@
distclean: clean
-@$(RM) $(JUNK) unittest *.o
$(MAKE) -C plugins $@
dist:
@echo "Building xz tarball of $(PKG) in parent dir..."
git archive --format=tar --prefix=$(PKG)/ $(VERSION) | xz >../$(ARCHIVE)
@(cd ..; md5sum $(ARCHIVE) | tee $(ARCHIVE).md5)
# Include automatically generated rules, such as:
# uncgi.o: .../some/dir/uncgi.c /usr/include/stdio.h
# but don't bother during clean!
ifneq ($(MAKECMDGOALS),clean)
ifneq ($(MAKECMDGOALS),distclean)
-include $(DEPS)
endif
endif
+116
View File
@@ -0,0 +1,116 @@
ACLOCAL_AMFLAGS = -I m4
sbin_PROGRAMS = finit initctl reboot
finit_SOURCES = api.c \
cond.c cond-w.c cond.h \
client.c \
conf.c conf.h \
exec.c finit.c finit.h \
getty.c \
helpers.c helpers.h \
mdadm.c mount.c pid.c \
plugin.c plugin.h private.h \
service.c service.h \
sig.c sig.h \
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)
if STATIC
finit_LDADD += plugins/libplug.la
else
finit_LDADD += -ldl
endif
initctl_SOURCES = initctl.c svc.c svc.h helpers.c helpers.h cond.c cond.h \
util.c util.h utmp-api.c utmp-api.h
initctl_CFLAGS = $(lite_CFLAGS)
initctl_LDADD = $(lite_LIBS)
reboot_SOURCES = reboot.c util.c util.h
INIT_LNKS = telinit init
REBOOT_LNKS = shutdown halt poweroff suspend
SUBDIRS = plugins
doc_DATA = README.md LICENSE finit.conf
EXTRA_DIST = README.md LICENSE ChangeLog.md finit.conf
AM_CPPFLAGS = -U_FORTIFY_SOURCE
AM_CPPFLAGS += -D_XOPEN_SOURCE=600 -D_BSD_SOURCE -D_GNU_SOURCE -D_DEFAULT_SOURCE
if STATIC
AM_CPPFLAGS += -DENABLE_STATIC
AM_LDFLAGS = -static-libtool-libs
else
AM_CPPFLAGS += -DPLUGIN_PATH=\"$(pkglibdir)\"
AM_LDFLAGS = -export-dynamic
endif
# Compat hook
install-dev: install-pkgincludeHEADERS
# Hook in install to add finit and reboot symlink(s)
install-exec-hook:
@for file in $(INIT_LNKS); do \
lnk=$(DESTDIR)$(sbindir)/$$file; \
if [ -e $$lnk ]; then \
echo "Skipping $$lnk exists already."; \
else \
$(LN_S) finit $$lnk; \
fi; \
done
@if [ -L $(DESTDIR)$(sbindir)/reboot ]; then \
echo "Non-finit reboot, skipping install."; \
else \
for file in $(REBOOT_LNKS); do \
link=$(DESTDIR)$(sbindir)/$$file; \
if [ -e $$link ]; then \
echo "$$link exists, skipping.";\
else \
$(LN_S) reboot $$link; \
fi; \
done; \
fi
uninstall-hook:
@for file in $(INIT_LNKS); do \
lnk=`readlink $(DESTDIR)$(sbindir)/$$file`; \
if [ "$$lnk" != "finit" ]; then \
echo "Skipping non-finit $$file."; \
continue; \
fi; \
$(RM) $(DESTDIR)$(sbindir)/$$file; \
done
@if [ -L $(DESTDIR)$(sbindir)/reboot ]; then \
echo "Non-finit reboot, skipping uninstall."; \
else \
for file in $(REBOOT_LNKS); do \
if [ "`readlink $$file`" != "reboot" ]; \
then continue; \
fi; \
$(RM) $(DESTDIR)$(sbindir)/$$file; \
done; \
fi
# Target to run when building a release
release: dist
@for file in $(DIST_ARCHIVES); do \
md5sum $$file > ../$$file.md5; \
done
@mv $(DIST_ARCHIVES) ../
@echo
@echo "Resulting release files:"
@echo "================================================================="
@for file in $(DIST_ARCHIVES); do \
printf "$$file \tDistribution tarball\n"; \
printf "$$file.md5\t"; cat ../$$file.md5 | cut -f1 -d' '; \
done
-1
View File
@@ -1 +0,0 @@
README.rst
+427
View File
@@ -0,0 +1,427 @@
<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)
* [/etc/finit.conf](doc/config.md#etcfinitconf)
* [/etc/finit.d](doc/config.md#etcfinitd)
* [Runparts & /etc/rc.local](#runparts--etcrclocal)
* [Bootstrap](doc/bootstrap.md#bootstrap)
* [Runlevels](#runlevels)
* [Inetd](doc/inetd.md#inetd)
* [Hooks, Callbacks & Plugins](doc/plugins.md#hooks-callbacks--plugins)
* [Rebooting & Halting](#rebooting--halting)
* [Commands & Status](#commands--status)
* [Building](doc/build.md#building)
* [Requirements](#requirements)
* [Running](#running)
* [Debugging](#debugging)
* [Origin & References](#origin--references)
Introduction
------------
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]. 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
long boot times. Finit reduces context switches and forking of shell
scripts to provide a swift [system bootstrap](doc/bootstrap.md) written
entirely in C.
Configuration is read from [/etc/finit.conf](doc/config.md#etcfinitconf)
which details kernel modules to load, services and TTYs to start. When
initial [bootstrap](doc/bootstrap.md) is done, including setting up
networking, [/etc/finit.d/](doc/config.md#etcfinitd) and the familiar
[/etc/rc.local](#runparts--etcrclocal) are run.
**Example /etc/finit.conf:**
```
# Fallback if /etc/hostname is missing
host wopr
# Runlevel to start after bootstrap, runlevel 'S'
runlevel 2
# Services to be monitored and respawned as needed
service [S12345] /sbin/watchdogd -L -f -- System watchdog daemon
service [S12345] /sbin/syslogd -n -b 3 -D -- System log daemon
service [S12345] /sbin/klogd -n -- Kernel log daemon
service [2345] /sbin/lldpd -d -c -M1 -H0 -i -- LLDP daemon (IEEE 802.1ab)
# For multiple instances of the same service, add :ID somewhere between
# the service/run/task keyword and the command.
service :1 [2345] /sbin/merecat -n -p 80 /var/www -- Web server
service :2 [2345] /sbin/merecat -n -p 8080 /var/www -- Old web server
# Alternative method instead of below runparts, can also use /etc/rc.local
#task [S] /etc/init.d/keyboard-setup start -- Setting up preliminary keymap
#task [S] /etc/init.d/acpid start -- Starting ACPI Daemon
#task [S] /etc/init.d/kbd start -- Preparing console
# Inetd services to start on demand, with alternate ports and filtering
inetd ftp/tcp nowait [2345] /sbin/uftpd -i -f -- FTP daemon
inetd tftp/udp wait [2345] /sbin/uftpd -i -y -- TFTP daemon
inetd time/udp wait [2345] internal -- UNIX rdate service
inetd time/tcp nowait [2345] internal -- UNIX rdate service
inetd 3737/tcp nowait [2345] internal.time -- UNIX rdate service
inetd telnet/tcp nowait [2345] /sbin/telnetd -i -F -- Telnet daemon
inetd 2323/tcp nowait [2345] /sbin/telnetd -i -F -- Telnet daemon
inetd 222/tcp@eth0 nowait [2345] /sbin/dropbear -i -R -F -- SSH service
inetd ssh/tcp@*,!eth0 nowait [2345] /sbin/dropbear -i -R -F -- SSH service
# Run start scripts from this directory
# runparts /etc/start.d
# Virtual consoles to start built-in getty on
tty [12345] /dev/tty1 115200 linux
tty [12345] /dev/ttyAMA0 115200 vt100
```
For an example of a full blown embedded Linux, see [TroglOS][9], or take
a look at the `contrib/` section with [Alpine Linux](contrib/alpine/),
[Debian](contrib/debian/), support and more.
Features
--------
**Process Supervision**
Start, monitor and restart services should they fail.
**Inetd**
Finit comes with a built-in [inetd server](doc/inetd.md). No need to
maintain a separate config file for services that you want to start on
demand.
All inetd services started can be filtered per port and inbound
interface, reducing the need for a full blown firewall.
Built-in optional inetd services:
- echo RFC862
- chargen RFC864
- daytime RFC867
- discard RFC863
- time (rdate) RFC868
For more information, see [doc/inetd.md](doc/inetd.md).
**Getty**
Finit also comes with a built-in Getty for Linux console TTYs. It can
parse `/etc/inittab` and set the speed. Then `/bin/login` handles all
nasty bits with PAM etc.
# /etc/finit.conf
tty [12345] /dev/tty1 38400 linux
tty [12345] /dev/ttyAMA0 115200 vt100
**Runlevels**
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**
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:
- **Hooks**
Hook into the boot at predefined points to extend Finit
- **I/O**
Listen to external events and control Finit behavior/services
- **Inetd**
Extend Finit with internal inetd services, for an example, see
`plugins/time.c`
Extensions and functionality not purely related to what an `/sbin/init`
needs to start a system are available as a set of plugins that either
hook into the boot process or respond to various I/O.
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
calls its built-in [run-parts(8)][] on the `runparts <DIR>` directory,
and `/etc/rc.local`, in that order if they exist.
```shell
runparts /etc/rc.d/
```
No configuration stanza in `/etc/finit.conf` is required for `rc.local`.
If it exists and is an executable shell script, finit calls it at the
very end of the boot, before calling the `HOOK_SYSTEM_UP`. See more on
hooks in [doc/plugins.md](doc/plugins.md#hooks), and about the system
bootstrap in [doc/bootstrap.md](doc/bootstrap.md).
Runlevels
---------
Basic support for [runlevels][5] is included in Finit from v1.8. By
default all services, tasks, run commands and TTYs listed without a set
of runlevels get a default set `[234]` assigned. The default runlevel
after boot is 2.
Finit supports runlevels 0-9, and S, with 0 reserved for halt, 6 reboot
and S for services to only run at bootstrap. Runlevel 1 is the single
user level, where usually no networking is enabled. In Finit this is
more of a policy for the user to define. Normally only runlevels 1-6
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:
```
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
service [S12345] /sbin/klogd -n -x -- Kernel log daemon
tty [12345] /dev/tty1
tty [2] /dev/tty2
tty [2] /dev/tty3
tty [2] /dev/tty4
tty [2] /dev/tty5
tty [2] /dev/tty6
```
In this example syslogd is first started, in parallel, and then acpid is
called using a conventional SysV init script. It is called with the run
command, meaning the following task command to start the kbd script is
not called until the acpid init script has fully completed. Then the
keyboard setup script is called in parallel with klogd as a monitored
service.
Again, tasks and services are started in parallel, while run commands
are called in the order listed and subsequent commands are not started
until a run command has completed.
Switching between runlevels can be done by calling init with a single
argument, e.g. <kbd>init 5</kbd> switches to runlevel 5. When changing
runlevels Finit also automatically reloads all `.conf` files in the
`/etc/finit.d/` directory. So if you want to set a new system config,
switch to runlevel 1, change all config files in the system, and touch
all `.conf` files in `/etc/finit.d` before switching back to the
previous runlevel again — that way Finit can both stop old services and
start any new ones for you, without rebooting the system.
Rebooting & Halting
-------------------
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.
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).
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.
~ # telinit -h
Usage: telinit [OPTIONS] [q | Q | 0-9]
Options:
-h, --help This help text
-V, --version Show Finit version
Commands:
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
-----------------
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.
~ $ initctl -h
Usage: initctl [OPTIONS] <COMMAND>
Options:
-d, --debug Debug initctl (client)
-v, --verbose Verbose output
-h, --help This help text
Commands:
debug Toggle Finit (daemon) debug
help This help text
reload Reload *.conf in /etc/finit.d/ and activate changes
runlevel [0-9] Show or set runlevel: 0 halt, 6 reboot
status | show Show status of services
cond set <COND> Set (assert) condition => +COND
cond clear <COND> Clear (deassert) condition => -COND
cond flux <COND> Emulate flux condition => ~COND
cond show Show condition status
start <JOB|NAME>[:ID] Start service by job# or name, with optional ID
stop <JOB|NAME>[:ID] Stop/Pause a running service by job# or name
restart <JOB|NAME>[:ID] Restart (stop/start) service by job# or name
reload <JOB|NAME>[:ID] Reload (SIGHUP) service by job# or name
version Show Finit version
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 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.
~ $ 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
3 running 478 [S12345] /sbin/klogd -n
4:1 inetd 0 [2345] internal time allow *:37
4:2 inetd 0 [2345] internal time allow *:37
4:3 inetd 0 [2345] internal 3737 allow *:3737
5:1 inetd 0 [2345] /sbin/telnetd allow *:23 deny eth0,eth1
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
-------
Having successfully [built Finit](doc/build.md) it may now be time to
take it for a test drive. The `make install` attempts to set up finit
as the system system init, `/sbin/init`, but this is usually a symlink
pointing to the current init.
So either change the symlink, or change your boot loader (GRUB, LOADLIN,
LILO, U-Boot/Barebox or RedBoot) configuration to append the following
to the kernel command line:
```shell
append="init=/sbin/finit"
```
Remember to also set up an initial `/etc/finit.conf` before rebooting!
![Finit starting TroglOS](images/finit3-screenshot.png "Finit screenshot")
Debugging
---------
Add `finit_debug`, or `--debug`, to the kernel command line to enable
debug messages.
```shell
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
-------------------
This project is based on the [original finit][] by [Claudio Matsuoka][]
which was reverse engineered from syscalls of the [EeePC fastinit][] —
"gaps filled with frog DNA …"
Finit is developed and maintained by [Joachim Nilsson][] at [GitHub][].
Please file bug reports, clone it, or send pull requests for bug fixes
and proposed extensions.
[1]: https://en.wikipedia.org/wiki/Process_supervision
[2]: http://cr.yp.to/daemontools.html
[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/
[EeePC fastinit]: http://wiki.eeeuser.com/boot_process:the_boot_process
[Claudio Matsuoka]: https://github.com/cmatsuoka
[Joachim Nilsson]: http://troglobit.com
[GitHub]: https://github.com/troglobit/finit
[Travis]: https://travis-ci.org/troglobit/finit
[Travis Status]: https://travis-ci.org/troglobit/finit.png?branch=master
[Coverity Scan]: https://scan.coverity.com/projects/3545
[Coverity Status]: https://scan.coverity.com/projects/3545/badge.svg
<!--
-- Local Variables:
-- mode: markdown
-- End:
-->
-169
View File
@@ -1,169 +0,0 @@
==============================================================================
Finit — A fast plugin-based /sbin/init with service monitoring
==============================================================================
Welcome to finit!
This is a heavily extended version of the original /sbin/init replacement
finit_. The original was a reimplementation of the EeePC "fastinit" daemon
based on its system calls with gaps filled with frog DNA.
Focus of this extended version is on small embedded GNU/Linux systems and
headless miniature servers with a need for extremely fast boot. In such
environments configurations rarely change and setup is rather static and
straight forward.
In the world of finit we write C "scripts" to boot our system, this is what
gives the system its raw performance and the user full control.
If you chose finit you know what you want, a fast boot with no hassle.
Features
--------
**Service monitoring**
Restarting a service when it exits
**Plugins**
Extend and modify finit behavior. See examples in plugins/ directory.
Plugin capabilities:
* Service callbacks — should the service run/restart/stop?
* Hooks — hook into the boot at predefined points to extend finit
* I/O — listen to external events and control finit behaviour/services
Most extensions and functionality not purely related to what an /sbin/init
needs to start a system from the original finit_ has been reactored into
plugins with either hooks or I/O demands.
/etc/finit.conf
---------------
Contrary to most script based init alternatives (SysV init_, upstart_, OpenRC_
and the likes) finit reads its configuration from /etc/finit.conf, see the
source code for available options.
Try out the examples/finit.conf for a Debian 6.0 example configuration
capable of service monitoring SSH, sysklogd, gdm and a console getty!
/etc/finit.d
------------
At the end of the boot, when networking and all services are up, finit calls
its built-in run-parts(8) on the /etc/finit.d/ directory, akin to how the
/ec/rc.local file works in most other inits, only finit runs a directory of
scripts. This replaces the earlier /usr/sbin/services.sh support of the
original finit_.
Rebooting and Halting
---------------------
Finit handles SIGUSR1 and SIGUSR2 for reboot and halt, and listens to
/dev/initctl so standard Linux reboot and halt commands should also
work.
Building
--------
The finit build system does not employ the GNU Configure and Build System,
instead standard makefiles are used. The user is encouraged to make source
code changes, using defines and conditionally building plugins instead to
alter the behavior of finit.
The following environment variables are checked by the makefiles and control
what is built and where resulting binaries are installed.
**ROOTDIR=**
Top directory for building complete system, used in pretty printing
**PLUGINS=**
List of stock finit plugins to build and install.
**PLUGIN_DIR=**
Absolute path to where finit should look for dynamically loadable plugins
at runtime. At installation prepended by ''DESTDIR'' and ''prefix''-
**VERSION=**
Defaults to the currently released version of finit, e.g., 1.2 but can
be overridden by packages to add a suffix or completely alter the version.
**CFLAGS=**
Standard CFLAGS are inherited from the build enviornmant.
**CPPFLAGS=**
Standard CPPFLAGS are inherited from the build enviornmant.
**LDFLAGS=**
Standard LDFLAGS are inherited from the build enviornmant.
**LDLIBS=**
Standard LIBLIBS are inherited from the build enviornmant.
**prefix=**
Path to where resulting binaries should install to. Used in concert
with the ''DESTDIR'' variable. Defaults to /usr/local
**sysconfdir=**
Used after ''prefix'' to create the path to finit.conf configuration
file. Defaults to /etc
**DESTDIR=**
Used by packagers and distributions when building a relocatable
bundle of files. Alwawys prepended to the ''prefix'' destination
directory.
**Example**::
$ tar xfJ finit-1.2.tar.xz
$ PLUGINS="initctl.so hwclock.so" prefix= DESTDIR=/tmp/finit/dst \
make -C finit-1.2/ clean install
make: Entering directory `/home/troglobit/finit-1.2'
CC finit.o
CC conf.o
CC helpers.o
CC sig.o
CC svc.o
CC plugin.o
CC strlcpy.o
LINK finit
CC plugins/initctl.o
PLUGIN plugins/initctl.so
CC plugins/hwclock.o
PLUGIN plugins/hwclock.so
INSTALL /tmp/finit/dst/sbin/finit
INSTALL /tmp/finit/dst/lib/finit/plugins/initctl.so
INSTALL /tmp/finit/dst/lib/finit/plugins/hwclock.so
make: Leaving directory `/home/troglobit/finit-1.2'
In this example the finit-1.2.tar.xz archive is unpacked to the user's
home directory, built and installed to a temporary staging directory.
The enviroment variables ''prefix'', ''DESTDIR'' and ''PLUGINS'' are all
changed to suit this particular build.
Debugging
---------
Add finit_debug, or --debug, to the kernel command line to enable trace
messages. A console getty is always started, see the file finit.h for
more useful comile-time tweaks.
Contact
-------
Finit is maintained collaborativly at https://github.com/troglobit/finit —
please file a bug report, clone it, or send pull requests for bug fixes and
proposed extensions, or become a co-maintainer by contacting the main author.
Regards
/Joachim Nilsson <troglobit@gmail.com>
.. _finit: http://helllabs.org/finit/
.. _init: http://savannah.nongnu.org/projects/sysvinit
.. _upstart: http://upstart.ubuntu.com/
.. _openrc: http://www.gentoo.org/proj/en/base/openrc/
-6
View File
@@ -1,6 +0,0 @@
* FHS changes, see http://askubuntu.com/questions/57297/why-has-var-run-been-migrated-to-run
* Look at Erik Troan's nash linuxrc parser for more inspiration
* Look at how to support a standard SysV init runlevel mechanism
* Arguments to finit, like to SysV init "init q" to reload finit.conf at runtime, etc.
* Implement initctl stop|start|reload <SVC> and service <SVC> stop|start|reload on top
* Write man pages for finit and finit.conf, steal from pimd man pages...
+115
View File
@@ -0,0 +1,115 @@
Goals of Finit
==============
The intent of finit is to monitor not just processes, but to supervise
an entire system and the behavior of certain processes that declare
themselves to be finit compliant. Similar to launchd, the goal of
finit is to be a replacement for:
* init
* inetd
* crond
* watchdogd
A small and simple replacement, primarily for embedded systems, with a
very low dependency on external packages.
General
-------
* Add halt/poweroff/shutdown symlinks to finit and convert reboot, but
only install symlinks if these tools don't already exist.
* 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.
* Add `finit.conf` support for UPS notification (SIGPWR) to start a task
using, e.g. <sys/power/{ok,fail,low}> conditions. More info in sig.c
* Add `finit.conf` support for ctrl-alt-delete (SIGINT) and kbrequest,
i.e. KeyboardSignal, (SIGWINCH) behavior. Using conditions to a task,
e.g, <sys/key/ctrlaltdel> and <sys/key/signal> like SIGPWR handling.
* Add `IFF_RUNNING` support to netlink plugin along `IFF_IUP`
* Allow process callbacks to be scripts.
* Add support for a pipe/popen where we can listen for `STOP`, `START`
and `RELOAD` on `STDOUT` from a script ... call it for example
`.monitor=` in `svc_t` ... the script named as the basename of the
service it monitors + `.sh`.
* Implement `initctl stop|start|restart|reload|status <SVC>` and
`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
Init
----
Finit in itself is not SysV Init compatible, it doesn't use `/etc/rc.d`
and `/etc/inet.d` scripts to boot the system. However, a plausible way
to achieve compatibility would be to add a plugin to finit which reads
`/etc/inittab` to be able to start standard Linux systems.
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.
* 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
-----
Requirements are quite rudimentary, basic cron functionality, mainly
system-level timed periodic tasks:
* Periodically run a task, in a matching runlevel
* Optionally run as non-root (`crontab -e` as operator)
Proposed syntax:
# Crontab
cron @YY-mm-ddTHH:MM [LVLS] /path/to/cmd [ARGS] -- Optional descr
# One-shot 'at' command
at @YY-mm-ddTHH:MM [LVLS] /path/to/cmd [ARGS] -- Optional descr
Notice the ISO date in notation. The runlevels is extra filtering
sugar. E.g., if cron service is only allowed in runlevels two or three
it will not start if system currently is in runlevel four.
To run a command as another user the `.conf` file must have a that
owner. E.g., `/etc/finit.d/extra.conf` may be owned by operator and
only hold `cron ...` lines.
What would be extremely useful is if `initctl`, or a homegrown `at`,
could support the basic functionality of the `at` command directly from
the shell -- that way setting up one-time jobs would not entail
re-reading `/etc/finit.conf`
Documentation
-------------
* Write man pages for finit and `finit.conf`, steal from the excellent
`pimd` man pages ...
* Add simple, *very* simple, `finit-simple.conf` example. To illustrate
how close Finit3 still is to the original easy-to-use Finit0 :)
[libwdt]: http://www.wehavemorefun.de/fritzbox/Libwdt.so
[Fritz!Box source dump]: ftp://ftp.avm.de/fritz.box/fritzbox.fon_wlan_7170/x_misc/opensrc/
<!--
-- Local Variables:
-- mode: markdown
-- End:
-->
+402
View File
@@ -0,0 +1,402 @@
/* External client API, using UNIX domain socket.
*
* Copyright (c) 2015 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 <errno.h>
#include <ctype.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <lite/lite.h>
#include <uev/uev.h>
#include "config.h"
#include "finit.h"
#include "cond.h"
#include "conf.h"
#include "helpers.h"
#include "plugin.h"
#include "sig.h"
#include "service.h"
uev_t api_watcher;
/* Allowed characters in job/id/name */
static int isallowed(int ch)
{
return isprint(ch);
}
/* Sanitize user input, make sure to NUL terminate. */
static char *sanitize(char *arg, size_t len)
{
size_t i = 0;
while (isallowed(arg[i]) && i < len)
i++;
if (i + 1 < len) {
arg[i + 1] = 0;
return arg;
}
return NULL;
}
static int call(int (*action)(svc_t *), char *buf, size_t len)
{
int result = 0;
char *input, *token, *pos;
input = sanitize(buf, len);
if (!input)
return -1;
token = strtok_r(input, " ", &pos);
while (token) {
svc_t *svc;
char *ptr = strchr(token, ':');
if (isdigit(token[0])) {
int job = atonum(token);
if (!ptr) {
svc = svc_job_iterator(1, job);
while (svc) {
result += action(svc);
svc = svc_job_iterator(0, job);
}
} else {
*ptr++ = 0;
job = atonum(token);
result += action(svc_find_by_jobid(job, atonum(ptr)));
}
} else {
if (!ptr) {
svc = svc_named_iterator(1, token);
while (svc) {
result += action(svc);
svc = svc_named_iterator(0, token);
}
} else {
*ptr++ = 0;
result += action(svc_find_by_nameid(token, atonum(ptr)));
}
}
token = strtok_r(NULL, " ", &pos);
}
return result;
}
static int service_block(svc_t *svc)
{
svc_block(svc);
service_step(svc);
return 0;
}
static int service_unblock(svc_t *svc)
{
svc_unblock(svc);
service_step(svc);
return 0;
}
static int service_restart(svc_t *svc)
{
svc_mark_dirty(svc);
service_step(svc);
return 0;
}
static int do_start (char *buf, size_t len) { return call(service_unblock, buf, len); }
static int do_pause (char *buf, size_t len) { return call(service_block, buf, len); }
static int do_restart(char *buf, size_t len) { return call(service_restart, buf, len); }
#ifndef INETD_DISABLED
static int do_query_inetd(char *buf, size_t len)
{
int id = 1;
char *ptr, *input = sanitize(buf, len);
svc_t *svc;
if (!input)
return -1;
ptr = strchr(input, ':');
if (ptr) {
*ptr++ = 0;
id = atonum(ptr);
}
svc = svc_find_by_jobid(atonum(input), id);
if (!svc || !svc_is_inetd(svc)) {
_e("Cannot %s svc %s ...", !svc ? "find" : "query, not an inetd", input);
return 1;
}
return inetd_filter_str(&svc->inetd, buf, len);
}
#endif /* !INETD_DISABLED */
typedef struct {
char *event;
void (*cb)(void);
} ev_t;
ev_t ev_list[] = {
{ "RELOAD", service_reload_dynamic },
{ NULL, NULL }
};
static int do_handle_event(char *event)
{
int i;
for (i = 0; ev_list[i].event; i++) {
ev_t *e = &ev_list[i];
size_t len = MAX(strlen(e->event), strlen(event));
if (!strncasecmp(e->event, event, len)) {
e->cb();
return 0;
}
}
if (event[0] == '-')
cond_clear(&event[1]);
else if (event[0] == '+')
cond_set(&event[1]);
else
cond_set(event);
return 0;
}
static int do_handle_emit(char *buf, size_t len)
{
int result = 0;
char *input, *event, *pos;
input = sanitize(buf, len);
if (!input)
return -1;
event = strtok_r(input, " ", &pos);
while (event) {
result += do_handle_event(event);
event = strtok_r(NULL, " ", &pos);
}
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, lvl;
struct init_request rq;
sd = accept(w->fd, NULL, NULL);
if (sd < 0) {
_pe("Failed serving API request");
return;
}
while (1) {
int result = 0;
ssize_t len;
len = read(sd, &rq, sizeof(rq));
if (len <= 0) {
if (-1 == len) {
if (EINTR == errno)
continue;
if (EAGAIN == errno)
break;
_e("Failed reading initctl request, error %d: %s", errno, strerror(errno));
}
break;
}
if (rq.magic != INIT_MAGIC || len != sizeof(rq)) {
_e("Invalid initctl request");
break;
}
switch (rq.cmd) {
case INIT_CMD_RUNLVL:
switch (rq.runlevel) {
case 's':
case 'S':
rq.runlevel = '1'; /* Single user mode */
/* Fall through to regular processing */
case '0'...'9':
_d("Setting new runlevel %c", rq.runlevel);
lvl = rq.runlevel - '0';
if (lvl == 0)
halt = SHUT_OFF;
if (lvl == 6)
halt = SHUT_REBOOT;
service_runlevel(lvl);
break;
default:
_d("Unsupported runlevel: %d", rq.runlevel);
break;
}
break;
case INIT_CMD_DEBUG:
debug = !debug;
if (debug)
silent = 0;
else
silent = quiet ? 1 : SILENT_MODE;
break;
case INIT_CMD_RELOAD: /* 'init q' and 'initctl reload' */
service_reload_dynamic();
break;
case INIT_CMD_START_SVC:
result = do_start(rq.data, sizeof(rq.data));
break;
case INIT_CMD_STOP_SVC:
result = do_pause(rq.data, sizeof(rq.data));
break;
case INIT_CMD_RESTART_SVC:
result = do_restart(rq.data, sizeof(rq.data));
break;
#ifndef INETD_DISABLED
case INIT_CMD_QUERY_INETD:
result = do_query_inetd(rq.data, sizeof(rq.data));
break;
#endif
case INIT_CMD_EMIT:
result = do_handle_emit(rq.data, sizeof(rq.data));
break;
case INIT_CMD_GET_RUNLEVEL:
rq.runlevel = runlevel;
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;
}
if (result)
rq.cmd = INIT_CMD_NACK;
else
rq.cmd = INIT_CMD_ACK;
len = write(sd, &rq, sizeof(rq));
if (len != sizeof(rq))
_d("Failed sending ACK/NACK back to client");
}
leave:
close(sd);
}
int api_init(uev_ctx_t *ctx)
{
int sd;
mode_t oldmask;
struct sockaddr_un sun = {
.sun_family = AF_UNIX,
.sun_path = INIT_SOCKET,
};
sd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
if (-1 == sd) {
_pe("Failed starting external API socket");
return 1;
}
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;
}
int api_exit(void)
{
return shutdown(api_watcher.fd, SHUT_RDWR) ||
close(api_watcher.fd);
}
/**
* Local Variables:
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/
Executable
+3
View File
@@ -0,0 +1,3 @@
#!/bin/sh
autoreconf -W portability -vifm
+160
View File
@@ -0,0 +1,160 @@
/* Simple telinit client
*
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
* Copyright (c) 2008-2015 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 */
#include <ctype.h>
#include <getopt.h>
#include <stdio.h>
#include <lite/lite.h>
#include "finit.h"
#include "util.h"
static int do_send(struct init_request *rq)
{
static int fd = -1;
int result = 255;
ssize_t len;
if (fd == -1) {
if (!fexist(FINIT_FIFO)) {
fprintf(stderr, "%s does not support %s!\n", prognm, FINIT_FIFO);
return 1;
}
fd = open(FINIT_FIFO, O_RDWR);
if (-1 == fd) {
perror("Failed opening " FINIT_FIFO);
return 1;
}
}
len = write(fd, rq, sizeof(*rq));
if (sizeof(*rq) == len)
result = 0;
return result;
}
static int do_reload(void)
{
struct init_request rq = {
.magic = INIT_MAGIC,
.cmd = INIT_CMD_RELOAD,
};
return do_send(&rq);
}
static int set_env(int runlevel)
{
struct init_request rq = {
.magic = INIT_MAGIC,
.cmd = INIT_CMD_SETENV,
};
if (runlevel == 0) {
strlcpy(rq.data, "INIT_HALT=POWERDOWN", sizeof(rq.data));
return do_send(&rq);
}
return 0;
}
static int set_runlevel(int runlevel)
{
struct init_request rq = {
.magic = INIT_MAGIC,
.cmd = INIT_CMD_RUNLVL,
.runlevel = runlevel,
};
return set_env(runlevel) || do_send(&rq);
}
/* telinit q | telinit <0-9> */
static int usage(int rc)
{
fprintf(stderr, "Usage: %s [OPTIONS] [q | Q | 0-9]\n\n"
"Options:\n"
" -h, --help This help text\n"
" -V, --version Show Finit version\n\n"
"Commands:\n"
" 0 Power-off the system, same as initctl poweroff\n"
" 6 Reboot the system, same as initctl reboot\n"
" 2, 3, 4, 5 Change runlevel. Starts services in new runlevel, stops any\n"
" services in prev. runlevel that are not allowed in new.\n"
" 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", prognm);
return rc;
}
int client(int argc, char *argv[])
{
int c;
struct option long_options[] = {
{"help", 0, NULL, 'h'},
{"version", 0, NULL, 'v'},
{NULL, 0, NULL, 0}
};
silent = 1;
progname(argv[0]);
while ((c = getopt_long(argc, argv, "h?v", long_options, NULL)) != EOF) {
switch(c) {
case 'v':
return puts("v" VERSION) == EOF;
case 'h':
case '?':
return usage(0);
}
}
if (optind < argc) {
int req = (int)argv[optind][0];
if (isdigit(req))
return set_runlevel(req);
if (req == 'q' || req == 'Q')
return do_reload();
if (req == 's' || req == 'S')
return set_runlevel(1);
}
return usage(1);
}
/**
* Local Variables:
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/
+19 -14
View File
@@ -1,25 +1,30 @@
# Top directory for building complete system, fall back to this directory
ROOTDIR ?= $(TOPDIR)
# Strip binaries unless user explicitly disables it
STRIPARGS ?= -s --strip-program=$(CROSS)strip -m 0755
# Some junk files we always want to be removed when doing a make clean. # Some junk files we always want to be removed when doing a make clean.
JUNK = *~ *.bak *.aux *.dvi *.idx *.ind *.log *.ps *.map .*.d DEADJOE semantic.cache *.gdb *.elf core core.* JUNK = *~ *.bak *.map .*.d *.d DEADJOE semantic.cache *.gdb *.elf core core.*
MAKE := @$(MAKE) MAKE := @$(MAKE)
MAKEFLAGS = --no-print-directory --silent MAKEFLAGS = --no-print-directory --silent
INSTALL := install -b CHECK := cppcheck $(CPPFLAGS) --quiet --enable=all
STRIPINST := $(INSTALL) -s --strip-program=$(CROSS)strip -m 0755 INSTALL := install --backup=off
STRIPINST := $(INSTALL) $(STRIPARGS)
ARFLAGS := crus
export libdir plugindir incdir ROOTDIR CPPFLAGS LDFLAGS LDLIBS STATIC
# Smart autodependecy generation via GCC -M.
.%.d: %.c
@$(SHELL) -ec "$(CC) -MM $(CFLAGS) $(CPPFLAGS) $< \
| sed 's,.*: ,$*.o $@ : ,g' > $@; \
[ -s $@ ] || rm -f $@"
# Override default implicit rules # Override default implicit rules
%.o: %.c %.o: %.c
@printf " CC $(subst $(ROOTDIR)/,,$(shell pwd)/$@)\n" @printf " CC $(subst $(ROOTDIR)/,,$(shell pwd)/$@)\n"
@$(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $< @$(CC) $(CFLAGS) $(CPPFLAGS) -c -MMD -MP -o $@ $<
%: %.o %: %.o
@printf " LINK $(subst $(ROOTDIR)/,,$(shell pwd)/$@)\n" @printf " LINK $(subst $(ROOTDIR)/,,$(shell pwd)/$@)\n"
@$(CC) $(CFLAGS) $(LDFLAGS) -Wl,-Map,$@.map -o $@ $^ $(LDLIBS$(LDLIBS-$(@))) @$(CC) $(CFLAGS) $(LDFLAGS) -Wl,-Map,$@.map -o $@ $^ $(LDLIBS$(LDLIBS-$(@)))
%.so: %.o %.so: %.o
@printf " PLUGIN $(subst $(ROOTDIR)/,,$(shell pwd)/$@)\n" @printf " PLUGIN $(subst $(ROOTDIR)/,,$(shell pwd)/$@)\n"
@$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) @$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS)
+132
View File
@@ -0,0 +1,132 @@
/* Condition engine (write)
*
* Copyright (c) 2015-2016 Tobias Waldekranz <tobias@waldekranz.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 <libgen.h>
#include <lite/lite.h>
#include <stdio.h>
#include <utime.h>
#include "finit.h"
#include "cond.h"
#include "service.h"
int cond_set_path(const char *path, enum cond_state new)
{
char buf[MAX_ARG_LEN], *dir;
enum cond_state old;
old = cond_get_path(path);
switch (new) {
case COND_ON:
strlcpy(buf, path, sizeof(buf));
dir = dirname(buf);
if (!dir) {
_e("Invalid path '%s' for condition", path);
return 0;
}
if (makepath(dir) && errno != EEXIST) {
_pe("Failed creating dir '%s' for condition '%s'", dir, path);
return 0;
}
touch(path);
utime(path, NULL);
break;
case COND_OFF:
unlink(path);
break;
default:
_e("Invalid condition state");
return 0;
}
return new != old;
}
/* Has condition in configuration and cond is allowed? */
static int svc_has_cond(svc_t *svc)
{
if (!svc->cond[0])
return 0;
switch (svc->type) {
case SVC_TYPE_SERVICE:
case SVC_TYPE_TASK:
case SVC_TYPE_RUN:
return 1;
default:
break;
}
return 0;
}
static void cond_update(const char *name)
{
svc_t *svc;
_d("%s", name);
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 ?: "nil", svc->cond, svc->cmd);
service_step(svc);
}
}
void cond_set(const char *name)
{
_d("%s", name);
if (!cond_set_path(cond_path(name), COND_ON))
return;
cond_update(name);
}
void cond_clear(const char *name)
{
_d("%s", name);
if (!cond_set_path(cond_path(name), COND_OFF))
return;
cond_update(name);
}
void cond_reload(void)
{
_d("");
cond_set_path(COND_RECONF, COND_ON);
cond_update(NULL);
}
/**
* Local Variables:
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/
+117
View File
@@ -0,0 +1,117 @@
/* Condition engine (read)
*
* Copyright (c) 2015-2016 Tobias Waldekranz <tobias@waldekranz.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 <lite/lite.h>
#include <stdio.h>
#include "finit.h"
#include "cond.h"
#include "service.h"
static inline int timespec_newer(const struct timespec *a,
const struct timespec *b)
{
if (a->tv_sec != b->tv_sec)
return a->tv_sec > b->tv_sec;
return a->tv_nsec > b->tv_nsec;
}
const char *condstr(enum cond_state s)
{
static const char *strs[] = {
[COND_OFF] = "off",
[COND_FLUX] = "flux",
[COND_ON] = "on",
};
return strs[s];
}
const char *cond_path(const char *name)
{
static char file[MAX_ARG_LEN];
snprintf(file, sizeof(file), COND_PATH "/%s", name);
return file;
}
enum cond_state cond_get_path(const char *path)
{
struct stat st, st_reconf;
if (stat(path, &st))
return COND_OFF;
if (stat(COND_RECONF, &st_reconf) ||
timespec_newer(&st.st_mtim, &st_reconf.st_mtim))
return COND_ON;
return COND_FLUX;
}
enum cond_state cond_get(const char *name)
{
return cond_get_path(cond_path(name));
}
enum cond_state cond_get_agg(const char *names)
{
char *cond;
enum cond_state s = COND_ON;
static char conds[MAX_ARG_LEN];
if (!names)
return COND_ON;
strlcpy(conds, names, sizeof(conds));
for (cond = strtok(conds, ","); s && cond; cond = strtok(NULL, ","))
s = min(s, cond_get(cond));
return s;
}
int cond_affects(const char *name, const char *names)
{
char *cond;
static char conds[MAX_ARG_LEN];
if (!name || !names)
return 0;
strlcpy(conds, names, sizeof(conds));
for (cond = strtok(conds, ","); cond; cond = strtok(NULL, ",")) {
if (!strcmp(cond, name))
return 1;
}
return 0;
}
/**
* Local Variables:
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/
+35
View File
@@ -0,0 +1,35 @@
#ifndef FINIT_COND_H_
#define FINIT_COND_H_
#include <paths.h>
#define COND_PATH _PATH_VARRUN "finit/cond"
#define COND_SVC_PATH COND_PATH "/svc/"
#define COND_RECONF COND_PATH "/reconf"
typedef enum cond_state {
COND_OFF = 0,
COND_FLUX,
COND_ON
} cond_state_t;
const char *condstr (enum cond_state s);
const char *cond_path (const char *name);
enum cond_state cond_get_path(const char *path);
enum cond_state cond_get (const char *name);
enum cond_state cond_get_agg (const char *names);
int cond_affects (const char *name, const char *names);
int cond_set_path(const char *path, enum cond_state new);
void cond_set (const char *name);
void cond_clear (const char *name);
void cond_reload (void);
#endif /* FINIT_COND_H_ */
/**
* Local Variables:
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/
+478 -99
View File
@@ -1,6 +1,6 @@
/* Parser for finit.conf /* Parser for /etc/finit.conf and /etc/finit.d/<SVC>.conf
* *
* Copyright (c) 2012 Joachim Nilsson <troglobit@gmail.com> * Copyright (c) 2012-2015 Joachim Nilsson <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -21,124 +21,503 @@
* THE SOFTWARE. * THE SOFTWARE.
*/ */
#include "config.h" /* Generated by configure script */
#include <dirent.h>
#include <string.h> #include <string.h>
#include <sys/resource.h>
#include <lite/lite.h>
#include "finit.h" #include "finit.h"
#include "svc.h" #include "cond.h"
#include "service.h"
#include "tty.h"
#include "helpers.h" #include "helpers.h"
/* Match one command. */ #define MATCH_CMD(l, c, x) \
#define MATCH_CMD(l, c, x) \ (!strncasecmp(l, c, strlen(c)) && (x = (l) + strlen(c)))
(!strncmp(l, c, strlen(c)) && (x = (l) + strlen(c)))
static int parse_conf(char *file);
static char *build_cmd(char *cmd, char *line, int len) void conf_parse_cmdline(void)
{
int l;
char *c;
/* Trim leading whitespace */
while (*line && (*line == ' ' || *line == '\t'))
line++;
if (!cmd) {
cmd = malloc (strlen(line) + 1);
if (!cmd) {
_e("No memory left for '%s'", line);
return NULL;
}
*cmd = 0;
}
c = cmd + strlen(cmd);
for (l = 0; *line && *line != '#' && *line != '\t' && l < len; l++)
*c++ = *line++;
*c = 0;
_d("cmd = %s", cmd);
return cmd;
}
void parse_finit_conf(char *file)
{ {
FILE *fp; FILE *fp;
char line[LINE_SIZE]; char line[LINE_SIZE];
char cmd[CMD_SIZE];
/* Default username and hostname */ fp = fopen("/proc/cmdline", "r");
username = strdup(DEFUSER); if (fp) {
hostname = strdup(DEFHOST); fgets(line, sizeof(line), fp);
_d("Kernel command line: %s", line);
if ((fp = fopen(file, "r")) != NULL) { if (strstr(line, "finit_debug") || strstr(line, "--debug"))
char *x; debug = 1;
_d("Parse %s ...", file); if (!debug && strstr(line, "quiet"))
while (!feof(fp)) { quiet = 1;
if (!fgets(line, sizeof(line), fp))
continue;
chomp(line);
_d("conf: %s", line);
/* Skip comments. */
if (MATCH_CMD(line, "#", x)) {
continue;
}
/* Do this before mounting / read-write */
if (MATCH_CMD(line, "check ", x)) {
strcpy(cmd, "/sbin/fsck -C -a ");
build_cmd(cmd, x, CMD_SIZE);
run_interactive(cmd, "Checking file system integrity on %s", x);
continue;
}
if (MATCH_CMD(line, "user ", x)) {
if (username) free(username);
username = build_cmd(NULL, x, USERNAME_SIZE);
continue;
}
if (MATCH_CMD(line, "host ", x)) {
if (hostname) free(hostname);
hostname = build_cmd(NULL, x, HOSTNAME_SIZE);
continue;
}
if (MATCH_CMD(line, "shutdown ", x)) {
if (sdown) free(sdown);
sdown = build_cmd(NULL, x, CMD_SIZE);
continue;
}
if (MATCH_CMD(line, "module ", x)) {
strcpy(cmd, "/sbin/modprobe ");
build_cmd(cmd, x, CMD_SIZE);
run_interactive(cmd, " Loading module %s", x);
continue;
}
if (MATCH_CMD(line, "mknod ", x)) {
strcpy(cmd, "/bin/mknod ");
build_cmd(cmd, x, CMD_SIZE);
run_interactive(cmd, " Creating device node %s", x);
continue;
}
if (MATCH_CMD(line, "network ", x)) {
if (network) free(network);
network = build_cmd(NULL, x, CMD_SIZE);
continue;
}
if (MATCH_CMD(line, "startx ", x)) {
svc_register(x, username);
continue;
}
if (MATCH_CMD(line, "service ", x)) {
svc_register(x, NULL);
continue;
}
}
fclose(fp); fclose(fp);
} }
} }
/* Convert optional "[!123456789S]" string into a bitmask */
int conf_parse_runlevels(char *runlevels)
{
int i, not = 0, bitmask = 0;
if (!runlevels)
runlevels = "[234]";
i = 1;
while (i) {
int level;
char lvl = runlevels[i++];
if (']' == lvl || 0 == lvl)
break;
if ('!' == lvl) {
not = 1;
bitmask = 0x3FE;
continue;
}
if ('s' == lvl || 'S' == lvl)
lvl = '0';
level = lvl - '0';
if (level > 9 || level < 0)
continue;
if (not)
CLRBIT(bitmask, level);
else
SETBIT(bitmask, level);
}
return bitmask;
}
void conf_parse_cond(svc_t *svc, char *cond)
{
size_t i = 0;
char *ptr;
if (!svc) {
_e("Invalid service pointer");
return;
}
/* By default we assume UNIX daemons support SIGHUP */
if (svc_is_daemon(svc))
svc->sighup = 1;
if (!cond)
return;
/* First character must be '!' if SIGHUP is not supported. */
ptr = cond;
if (ptr[i] == '!') {
svc->sighup = 0;
ptr++;
}
while (ptr[i] != '>' && ptr[i] != 0)
i++;
ptr[i] = 0;
if (i >= sizeof(svc->cond)) {
logit(LOG_WARNING, "Too long event list in declaration of %s: %s", svc->cmd, ptr);
return;
}
strlcpy(svc->cond, ptr, sizeof(svc->cond));
}
struct rlimit_name {
char *name;
int val;
};
static const struct rlimit_name rlimit_names[] = {
{ "as", RLIMIT_AS },
{ "core", RLIMIT_CORE },
{ "cpu", RLIMIT_CPU },
{ "data", RLIMIT_DATA },
{ "fsize", RLIMIT_FSIZE },
{ "locks", RLIMIT_LOCKS },
{ "memlock", RLIMIT_MEMLOCK },
{ "msgqueue", RLIMIT_MSGQUEUE },
{ "nice", RLIMIT_NICE },
{ "nofile", RLIMIT_NOFILE },
{ "nproc", RLIMIT_NPROC },
{ "rss", RLIMIT_RSS },
{ "rtprio", RLIMIT_RTPRIO },
#ifdef RLIMIT_RTTIME
{ "rttime", RLIMIT_RTTIME },
#endif
{ "sigpending", RLIMIT_SIGPENDING },
{ "stack", RLIMIT_STACK },
{ NULL, 0 }
};
void conf_parse_rlimit(char *line)
{
struct rlimit rlim;
rlim_t new, *set;
const struct rlimit_name *name;
int resource = -1;
char *tok = strtok(line, " \t");
if (tok && !strcmp(tok, "soft"))
set = &rlim.rlim_cur;
else if (tok && !strcmp(tok, "hard"))
set = &rlim.rlim_max;
else
goto error;
tok = strtok(NULL, " \t");
if (!tok)
goto error;
for (name = rlimit_names; name->name; name++) {
if (!strcmp(tok, name->name))
resource = name->val;
}
if (resource < 0)
goto fail;
tok = strtok(NULL, " \t");
if (!tok)
goto fail;
if (!strcmp(tok, "infinity")) {
new = RLIM_INFINITY;
} else {
const char *err = NULL;
new = strtonum(tok, 0, (long long)2 << 31, &err);
if (err)
goto fail;
}
if (getrlimit(resource, &rlim))
goto fail;
*set = new;
if (setrlimit(resource, &rlim))
goto fail;
return;
fail:
logit(LOG_WARNING, "rlimit: Failed setting rlimit %s", name->name ? : "unknown");
return;
error:
logit(LOG_WARNING, "rlimit: parse error");
}
static void parse_static(char *line)
{
char *x;
char cmd[CMD_SIZE];
/* Do this before mounting / read-write
* XXX: Move to plugin which checks /etc/fstab instead */
if (MATCH_CMD(line, "check ", x)) {
char *dev = strip_line(x);
strcpy(cmd, "/sbin/fsck -C -a ");
strlcat(cmd, dev, sizeof(cmd));
run_interactive(cmd, "Checking file system %s", dev);
return;
}
if (MATCH_CMD(line, "user ", x)) {
if (username) free(username);
username = strdup(strip_line(x));
return;
}
if (MATCH_CMD(line, "host ", x)) {
if (hostname) free(hostname);
hostname = strdup(strip_line(x));
return;
}
if (MATCH_CMD(line, "module ", x)) {
char *mod = strip_line(x);
strcpy(cmd, "/sbin/modprobe ");
strlcat(cmd, mod, sizeof(cmd));
run_interactive(cmd, "Loading kernel module %s", mod);
return;
}
if (MATCH_CMD(line, "mknod ", x)) {
char *dev = strip_line(x);
strcpy(cmd, "/bin/mknod ");
strlcat(cmd, dev, sizeof(cmd));
run_interactive(cmd, "Creating device node %s", dev);
return;
}
if (MATCH_CMD(line, "network ", x)) {
if (network) free(network);
network = strdup(strip_line(x));
return;
}
if (MATCH_CMD(line, "runparts ", x)) {
if (runparts) free(runparts);
runparts = strdup(strip_line(x));
return;
}
if (MATCH_CMD(line, "include ", x)) {
char *file = strip_line(x);
strlcpy(cmd, file, sizeof(cmd));
if (!fexist(cmd)) {
_e("Cannot find include file %s, absolute path required!", x);
return;
}
parse_conf(cmd);
return;
}
if (MATCH_CMD(line, "startx ", x)) {
service_register(SVC_TYPE_SERVICE, strip_line(x), 0, username);
return;
}
if (MATCH_CMD(line, "shutdown ", x)) {
if (sdown) free(sdown);
sdown = strdup(strip_line(x));
return;
}
/* The desired runlevel to start when leaving bootstrap (S).
* Finit supports 1-9, but most systems only use 1-6, where
* 6 is reserved for reboot */
if (MATCH_CMD(line, "runlevel ", x)) {
char *token = strip_line(x);
const char *err = NULL;
cfglevel = strtonum(token, 1, 9, &err);
if (err)
cfglevel = RUNLEVEL;
if (cfglevel < 1 || cfglevel > 9 || cfglevel == 6)
cfglevel = 2; /* Fallback */
return;
}
/* TODO: Make console & tty dynamically loadable from /etc/finit.d */
if (MATCH_CMD(line, "console ", x)) {
if (console) free(console);
console = strdup(strip_line(x));
return;
}
/* TODO: Make console & tty dynamically loadable from /etc/finit.d */
if (MATCH_CMD(line, "tty ", x)) {
tty_register(strip_line(x));
return;
}
}
static void parse_dynamic(char *line, time_t mtime)
{
char *x;
/* Skip comments, i.e. lines beginning with # */
if (MATCH_CMD(line, "#", x))
return;
/* 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 */
if (MATCH_CMD(line, "task ", x)) {
service_register(SVC_TYPE_TASK, x, mtime, NULL);
return;
}
/* Like task but waits for completion, useful w/ [S] */
if (MATCH_CMD(line, "run ", x)) {
service_register(SVC_TYPE_RUN, x, mtime, NULL);
return;
}
/* Classic inetd service */
if (MATCH_CMD(line, "inetd ", x)) {
#ifndef INETD_DISABLED
service_register(SVC_TYPE_INETD, x, mtime, NULL);
#else
_e("Finit built with inetd support disabled, cannot register service inetd %s!", x);
#endif
return;
}
if (MATCH_CMD(line, "rlimit ", x)) {
conf_parse_rlimit(x);
return;
}
}
static void tabstospaces(char *line)
{
if (!line)
return;
for (int i = 0; line[i]; i++) {
if (line[i] == '\t')
line[i] = ' ';
}
}
static int parse_conf_dynamic(char *file, time_t mtime)
{
FILE *fp = fopen(file, "r");
if (!fp) {
_pe("Failed opening %s", file);
return 1;
}
while (!feof(fp)) {
char line[LINE_SIZE] = "";
if (!fgets(line, sizeof(line), fp))
continue;
chomp(line);
tabstospaces(line);
_d("dyn conf: %s", line);
parse_dynamic(line, mtime);
}
fclose(fp);
return 0;
}
static int parse_conf(char *file)
{
FILE *fp;
char line[LINE_SIZE] = "";
char *x;
fp = fopen(file, "r");
if (!fp)
return 1;
/*
* If not standard finit.conf, then we want to show just the base name
* Loading configuration ............. vs
* Loading services configuration ....
*/
if (!string_match (file, FINIT_CONF)) {
/* Remove leading path */
x = strrchr(file, '/');
if (!x) x = file;
else x++;
/* Remove ending .conf */
strlcpy(line, x, sizeof(line));
x = strstr(line, ".conf");
if (x) *x = 0;
/* Add empty space. */
strcat(line, " ");
}
if (!silent)
print(0, "Loading %sconfiguration", line);
while (!feof(fp)) {
if (!fgets(line, sizeof(line), fp))
continue;
chomp(line);
tabstospaces(line);
_d("conf: %s", line);
parse_static(line);
parse_dynamic(line, 0);
}
fclose(fp);
return 0;
}
/* Reload all *.conf in /etc/finit.d/ */
void conf_reload_dynamic(void)
{
int i, num;
char *dir = rcsd;
struct dirent **e;
/* Mark and sweep */
svc_mark_dynamic();
num = scandir(dir, &e, NULL, alphasort);
if (num < 0) {
_d("No files found in %s, skipping ...", dir);
return;
}
for (i = 0; i < num; i++) {
char *name = e[i]->d_name;
char path[CMD_SIZE];
struct stat st;
snprintf(path, sizeof(path), "%s/%s", dir, name);
/* Check that it's an actual file ... */
if (stat(path, &st)) {
_d("Cannot even read .conf file %s, skipping ...", path);
continue;
}
if (S_ISEXEC(st.st_mode) || S_ISDIR(st.st_mode))
continue;
/* Check that file ends with '.conf' */
if (strcmp(&path[strlen(path) - 5], ".conf")) {
_d("File %s is not a .conf, skipping ... ", path);
continue;
}
parse_conf_dynamic(path, st.st_mtime);
}
while (num--)
free(e[num]);
free(e);
set_hostname(&hostname);
}
int conf_parse_config(void)
{
username = strdup(DEFUSER);
hostname = strdup(DEFHOST);
return parse_conf(FINIT_CONF);
}
/** /**
* Local Variables: * Local Variables:
* version-control: t
* indent-tabs-mode: t * indent-tabs-mode: t
* c-file-style: "linux" * c-file-style: "linux"
* End: * End:
+42
View File
@@ -0,0 +1,42 @@
/* Parser for /etc/finit.conf and /etc/finit.d/<SVC>.conf
*
* Copyright (c) 2012-2015 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_CONF_H_
#define FINIT_CONF_H_
#include "svc.h"
void conf_parse_cmdline (void);
int conf_parse_runlevels (char *runlevels);
void conf_parse_cond (svc_t *svc, char *cond);
int conf_parse_config (void);
void conf_reload_dynamic (void);
#endif /* FINIT_CONF_H_ */
/**
* Local Variables:
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/
+215
View File
@@ -0,0 +1,215 @@
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])
AC_CONFIG_SRCDIR([finit.c])
AC_CONFIG_HEADER([config.h])
AC_CONFIG_FILES([Makefile plugins/Makefile])
# Older versions of autoconf (<2.58) do not have AC_CONFIG_MACRO_DIR()
#m4_include([m4/plugin.m4])
#m4_include([m4/expand.m4])
AC_CONFIG_MACRO_DIR([m4])
# Change default prefix, we're PID 1 after all ...
AC_PREFIX_DEFAULT([])
# Handle building plugins either as dynamically loadable, or built-in
LT_INIT([shared disable-static dlopen aix-soname=both disable-fast-install])
# Checks for programs.
AC_PROG_CC
AC_PROG_LN_S
AC_PROG_INSTALL
# Configuration.
AC_HEADER_STDC
AC_CHECK_HEADERS(fstaby.h)
AC_CHECK_FUNCS(strstr getopt getfsenty)
# Check for uint[8,16,32]_t
AC_TYPE_UINT8_T
AC_TYPE_UINT16_T
AC_TYPE_UINT32_T
# Check for required libraries
PKG_CHECK_MODULES([uev], [libuev >= 1.5.2])
PKG_CHECK_MODULES([lite], [libite >= 1.8.2])
# Check for configured Finit features
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]))
AC_ARG_ENABLE(quiet,
AS_HELP_STRING([--disable-quiet], [Default Finit obeys the kernel quiet option]))
# Check for extra plugins to enable
enable_all_plugins=auto
AC_PLUGIN([alsa-utils], [no], [Save and restore ALSA sound settings using alsactl])
AC_PLUGIN([dbus], [no], [Setup and start system message bus, D-Bus])
AC_PLUGIN([inetd-echo], [no], [Inetd plugin: echo server, RFC862])
AC_PLUGIN([inetd-chargen], [no], [Inetd plugin: character generator, RFC864])
AC_PLUGIN([inetd-daytime], [no], [Inetd plugin: daytime server, RFC867])
AC_PLUGIN([inetd-discard], [no], [Inetd plugin: discard server, RFC863])
AC_PLUGIN([inetd-time], [no], [Inetd plugin: time (rdate) server, RFC868])
AC_PLUGIN([lost], [no], [Example HOOK_SVC_LOST plugin, very noisy as-is!])
AC_PLUGIN([resolvconf], [no], [Setup necessary files for resolvconf])
AC_PLUGIN([x11-common], [no], [Console setup (for X)])
AC_PLUGIN([netlink], [yes], [Basic netlink plugin for IFUP/IFDN and GW events. Can be replaced with externally built plugin that links with libnl or similar.])
# Check for extra arguments or packages
AC_ARG_WITH(heading,
AS_HELP_STRING([--with-heading=GREET], [Display GREET instead of Finit version at boot]),
[heading=$withval], [heading="$PACKAGE_NAME v$PACKAGE_VERSION"])
AC_ARG_WITH(fifo,
AS_HELP_STRING([--with-fifo=FIFO], [FIFO for init/telinit clients, default /var/run/initctl]),
[fifo=$withval], [fifo=/var/run/initctl])
AC_ARG_WITH(plugindir,
AS_HELP_STRING([--with-plugindir=DIR], [Finit plugin directory, default /lib/finit/plugins]),
[pkglibdir=$withval], [pkglibdir=$libdir/finit/plugins])
AC_SUBST([pkglibdir])
AC_ARG_WITH(config,
AS_HELP_STRING([--with-config=CONFIG], [Finit bootstrap config file, default /etc/finit.conf]),
[conf=$withval], [conf=$sysconfdir/finit.conf])
AC_ARG_WITH(rcsd,
AS_HELP_STRING([--with-rcsd=DIR], [Finit rcS.d/ directory, default /etc/finit.d]),
[rcsd=$withval], [rcsd=$sysconfdir/finit.d])
AC_ARG_WITH(rc-local,
AS_HELP_STRING([--with-rc-local=FILE], [SysV init /etc/rc.local file, default /etc/rc.local]),
[rclocal=$withval], [rclocal=$sysconfdir/rc.local])
AC_ARG_WITH(console,
AS_HELP_STRING([--with-console=DEV], [Console to use, default: /dev/console]),
[console=$withval], [console=/dev/console])
AC_ARG_WITH(username,
AS_HELP_STRING([--with-username=USER], [User for 'startx' .conf option, default: root]),
[username=$withval], [username=root])
AC_ARG_WITH(hostname,
AS_HELP_STRING([--with-hostname=NAME], [If /etc/hostname is missing, default: noname]),
[hostname=$withval], [hostname=noname])
AC_ARG_WITH(runlevel,
AS_HELP_STRING([--with-runlevel=N], [Runlevel to switch to after bootstrap, default: 2]),
[runlevel=$withval], [runlevel=2])
AC_ARG_WITH(random-seed,
AS_HELP_STRING([--with-random-seed=FILE], [Save a random seed for /dev/urandom across reboots, default /var/lib/misc/random-seed]),
[random_seed=$withval], [random_seed=/var/lib/misc/random-seed])
### Enable features ###########################################################################
# Create config.h from selected features and fallback defautls
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])])
AS_IF([test "x$enable_silent" = "xyes"], [
AC_DEFINE(SILENT_MODE, 1, [Completely silent operation, not even boot messages])
], [
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", [
AC_DEFINE(INETD_DISABLED, 1, [Disable built-in inetd])])
AS_IF([test "x$enable_quiet" != "xno"], [
AC_DEFINE(QUIET_MODE, 1, [Silent, after initial boot, no stopping/starting messages. Default: 1])
], [
AC_DEFINE(QUIET_MODE, 0, [Silent, after initial boot, no stopping/starting messages. Default: 1])])
### With features ##############################################################################
AS_IF([test "x$with_fifo" != "xno"], [
AS_IF([test "x$fifo" = "xyes"], [
fifo='/var/run/initctl'])])
AC_EXPAND_DIR(lurvig, "$fifo")
AC_DEFINE_UNQUOTED(FINIT_FIFO, "$lurvig", [FIFO for old style init/telinit client programs])
AS_IF([test "x$with_config" != "xno"], [
AS_IF([test "x$config" = "xyes"], [
conf=$sysconfdir/finit.conf])])
AC_EXPAND_DIR(lurvig, "$conf")
AC_DEFINE_UNQUOTED(FINIT_CONF, "$lurvig", [Main Finit configuration file, default /etc/finit.conf])
AS_IF([test "x$with_rcsd" != "xno"], [
AS_IF([test "x$rcsd" = "xyes"], [
rcsd=$sysconfdir/finit.d])])
AC_EXPAND_DIR(lurvig, "$rcsd")
AC_DEFINE_UNQUOTED(FINIT_RCSD, "$lurvig", [Finit rcS.d/, default /etc/finit.d])
AS_IF([test "x$with_rc_local" != "xno"], [
AS_IF([test "x$rclocal" = "xyes"], [
rclocal=$sysconfdir/rc.local])])
AC_EXPAND_DIR(lurvig, "$rclocal")
AC_DEFINE_UNQUOTED(FINIT_RC_LOCAL, "$lurvig", [Compat SysV /etc/rc.local file to run last at boot.])
AS_IF([test "x$with_heading" != "xno"], [
AS_IF([test "x$heading" = "xyes"], [
heading="$PACKAGE_NAME v$PACKAGE_VERSION"])])
AC_DEFINE_UNQUOTED(INIT_HEADING, "$heading", [Displayed by Finit at boot])
AS_IF([test "x$with_console" != "xno"], [
AS_IF([test "x$console" = "xyes"], [
console=/dev/console])])
AC_DEFINE_UNQUOTED(CONSOLE, "$console", [Default console to use])
AS_IF([test "x$with_username" != "xno"], [
AS_IF([test "x$username" = "xyes"], [
username=root])])
AC_DEFINE_UNQUOTED(DEFUSER, "$username", [Used for startx .conf option])
AS_IF([test "x$with_hostname" != "xno"], [
AS_IF([test "x$hostname" = "xyes"], [
hostname=noname])])
AC_DEFINE_UNQUOTED(DEFHOST, "$hostname", [For /etc/hostname])
AS_IF([test "x$with_runlevel" != "xno"], [
AS_IF([test "x$runlevel" = "xyes"], [
AC_DEFINE_UNQUOTED(RUNLEVEL, 2, [Default runlevel to start after S])])
AC_DEFINE_UNQUOTED(RUNLEVEL, $runlevel, [Runlevel to start after S])])
AS_IF([test "x$with_random_seed" != "xno"], [
AS_IF([test "x$random_seed" = "xyes"], [
random_seed=/var/lib/misc/random-seed])
AC_EXPAND_DIR(lurvig, "$random_seed")
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(WATCHDOGD, [test "x$enable_watchdog" = "xyes"])
# Generate all files
AC_OUTPUT
+12
View File
@@ -0,0 +1,12 @@
Finit Examples
==============
This section provides configuration examples and helpful tools to
install and try out Finit on various Linux distributions.
* [Alpine](alpine/)
* [Debian](debian/)
If you have ideas on how to simplify, extend, or even add new example
configurations for other distributions you are most welcome! :)
+46
View File
@@ -0,0 +1,46 @@
HowTo: Finit on Alpine Linux 3.4
================================
Mini HowTo using Finit to boot an Alpine Linux system. It is assumed
that the user has already installed a compiler, C library header files,
and other tools needed to build a GNU configure based project.
To start with you need to first install [libuEv][] and [libite][], by
default they install to `/usr/local` and Alpine's `pkg-config` does not
look for libraries and header files there. So the `PKG_CONFIG_LIBDIR`
environment variable has to be used:
alpine:~/finit# PKG_CONFIG_LIBDIR=/usr/local/lib/pkgconfig ./configure \
--enable-rw-rootfs --enable-x11-common-plugin \
--enable-alsa-utils-plugin --enable-inetd-echo-plugin \
--enable-inetd-chargen-plugin --enable-inetd-daytime-plugin \
--enable-inetd-discard-plugin --enable-inetd-time-plugin \
--with-heading="Alpine Linux 3.4" --with-hostname=alpine
The plugins are optional, but the other configure flags are *not*.
alpine:~/finit# make all install
The installation skips `/sbin/init`, because it already exists, and
Alpine is hard coded to use it. So you have to change the symlink
yourself to point to `finit` instead of `/bin/busybox`.
alpine:~/finit# cd /sbin
alpine:/sbin# rm init
alpine:/sbin# ln -s finit init
Before rebooting, make sure to set up a [/etc/finit.conf](finit.conf),
and possibly also an [/etc/rc.local](rc.local) for one-shot set up and
initialization like keyboard language etc. You can use the files in
this directory as templates -- check them both if they need to be
tweaked for your installation, you may not run Dropbear SSH or speak
Swedish ...
[libuEv]: https://github.com/troglobit/libuev
[libite]: https://github.com/troglobit/libite
<!--
-- Local Variables:
-- mode: markdown
-- End:
-->
+40
View File
@@ -0,0 +1,40 @@
# /etc/finit.conf: Example for Alpine Linux 3.4
# Modules to load
#module qxl
#module fbcon
module button
module evdev
# Runlevel to start after bootstrap, runlevel 'S'
runlevel 2
# Services to be monitored and respawned as needed
service [S12345] /sbin/klogd -n -- Kernel log daemon
service [S12345] /sbin/syslogd -n -- Syslog daemon
# Network bringup script, blocks boot like run stanza, use below task instead
#network /sbin/ifup -a
### Every line below can be a service/task per file in /etc/finit.d/*.conf ###
# Network bringup not needed if /etc/network/interfaces is used.
task [2345] log <svc/sbin/syslogd> /sbin/ifup -a -- Networking
# Depends on syslogd having started. Redirect any output to log.
service [2345] log <svc/sbin/syslogd> /usr/sbin/acpid -f -- ACPI daemon
# Silly Busybox ntpd has no option to use syslog when running in foreground
service [2345] log <svc/sbin/syslogd> /usr/sbin/ntpd -n -N -p pool.ntp.org
# Start SSH daemon as soon as basic networking comes up
service [2345] <net/lo/up> /usr/sbin/dropbear -R -F -p 22 -- Dropbear SSH daemon
service [2345] <svc/sbin/syslogd> /usr/sbin/crond -f -S -c /etc/crontabs -- Cron daemon
# Handle PWR button to shutdown/reboot -- useful in Qemu (virt-manager)
service [2345] /sbin/acpid -f -- ACPI daemon
# Consoles to start getty on when system is up
tty /dev/tty1
tty /dev/tty2
tty /dev/tty3
+2
View File
@@ -0,0 +1,2 @@
#!/bin/sh
zcat /etc/keymap/sv-latin1.bmap.gz | loadkmap
+52
View File
@@ -0,0 +1,52 @@
HowTo: Finit on Debian Jessie
=============================
Mini HowTo using Finit to boot Debian GNU/Linux 8.5 (Jessie). It is
assumed that the user has already installed a compiler, C library header
files, and other tools needed to build a GNU configure based project.
Also, Finit has only been verified to work with the Debian *Server* ed.
I.e., during install — skip GNOME and other X stuff to get a plain and
usable Debian server install, which we can add X-Window to later :-)
Now, I started off by replacing systemd from the base install with the
old SysV init, using [this HowTo][1], you may not need to do that, but
for me it was easier — and also a great rebuttal to all the systemd
haters out there (yeah, even though I speak for the alternative PID 1
movement I don't hate systemd :P) it is possible to still run Debian
without systemd! Anyway, this text was based on that experience.
Like the [Alpine HowTo](../alpine/), you need to install [libuEv][] and
[libite][], but since this is Debian — which takes infinite care of its
users ♥ ♥ ♥ we don't need to worry about `pkg-config`, except for having
it installed so it can locate the uEv and lite libraries.
> With Debian everything just works!™
The following build and install script can be used to configure, build,
install and set up your system to run Finit:
debian:~/finit$ contrib/debian/build.sh
Since `/sbin/init` already exists on your system the script creates
another entry in your GRUB config, in `/etc/grub.d/40_custom`, where
`init=/sbin/finit` is added to your kernel line. You could of course
also change the `/sbin/init` symlink and uninstall systemd/SysV init if
everything works fine, but that's up to you.
Before rebooting, read up on [/etc/finit.conf](finit.conf) and notice
how `/etc/start.d/` and `/etc/rc.local` can be used to extend the boot
with simpler setup tasks on your system — see the docu for details.
Have fun!
/Joachim ツ
[1]: http://without-systemd.org/wiki/index.php/How_to_remove_systemd_from_a_Debian_jessie/sid_installation
[libuEv]: https://github.com/troglobit/libuev
[libite]: https://github.com/troglobit/libite
<!--
-- Local Variables:
-- mode: markdown
-- End:
-->
+62
View File
@@ -0,0 +1,62 @@
#!/bin/sh
#
# This script configures Finit for Debian, which needs a few more plugins
# and tweaks than an embedded system usually does.
#
# Usage:
# user@jessie:~/finit$ contrib/debian/build.sh
#
echo
echo "*** Configuring Finit for Debian"
if [ ! -e configure ]; then
echo " The configure script is missing, maybe you're using a GIT checkout?"
echo " Attempting to run the autogen.sh script, you need these tools:"
echo " autoconf, automake, libtool, pkg-config ..."
echo
./autogen.sh
fi
echo
./configure --enable-rw-rootfs --enable-dbus-plugin --enable-x11-common-plugin \
--enable-alsa-utils-plugin --with-random-seed=/var/lib/urandom/random-seed \
--with-heading="Debian GNU/Linux 8.5" --with-hostname=jessie \
--enable-inetd-echo-plugin --enable-inetd-chargen-plugin \
--enable-inetd-daytime-plugin --enable-inetd-discard-plugin \
--enable-inetd-time-plugin
if [ $? -ne 0 ]; then
echo
echo "*** Configure script failed, have you installed libuEV and libite?"
echo
exit 1
fi
echo
echo "*** Building ..."
echo
make
if [ $? -ne 0 ]; then
echo
echo "*** The build failed for some reason"
echo
exit 1
fi
echo
echo "*** Done"
echo
read -p "*** Run (sudo) install script (y/N)? " yorn
if [ "x$yorn" = "xy" -o "x$yorn" = "xY" ]; then
sudo contrib/debian/install.sh
else
echo
echo "*** Use 'sudo contrib/debian/install.sh' later to install Finit"
echo
fi
+60
View File
@@ -0,0 +1,60 @@
# /etc/finit.conf: Example for Debian GNU/Linux 8.5
# Here we use one big (?) finit.conf, but all non-bootstrap services
# can just as easily be listed in a separate /etc/finit.d/*.conf
# The host directive is a fallback if /etc/hostname is missing
host jessie
# The user directive is only for the startx directive, which in turn is
# just like a service but with a different user. Services can also run
# with a different user, using the @username syntax
user root
# Linux kernel modules to load, /etc/modprobe is not used
module button
module evdev
module loop
module psmouse
# Runlevel to start after bootstrap, runlevel 'S'.
# Change this to 3 to start XDM at boot.
runlevel 2
# Some services may need to start very early, e.g. a watchdog daemon.
# Runlevel [S] (bootStrap) is useful for that. It cannot be switched
# to at runtime either, so tasks and run directives usually live here.
# Please note, the run directive is blocking, so be careful!
#service [S12345] /sbin/watchdogd -n -- Watchdog daemon
#run [S] /sbin/probe -- system probe
#run [S] /sbin/setupd --bootstrap -- system bootstrap
service [S12345] /usr/sbin/rsyslogd -n -- Syslog daemon
# Network bringup script not needed if /etc/network/interfaces is used
#network service networking start
# Regular services to be monitored and respawned as needed. Here we use
# a (svc) condition, the listed service must be started (waits for the
# PID file to be created in /run/*.pid) before starting either service,
# (net) conditions are also available.
service [2345] <svc/usr/sbin/rsyslogd> log /usr/sbin/acpid -f -- ACPI daemon
service [2345] <svc/usr/sbin/rsyslogd> /usr/sbin/sshd -D -- SSH daemon
# Here we use XDM since it has few dependencies (relatively speaking).
# It is also an example of a service (startx is an alias for service)
# that does not have a -- description.
#service [3] /usr/sbin/lightdm -- X-Window Display Manager
startx [3] /usr/bin/xdm -nodaemon
# Run old-style start scripts from this directory. Very similar to how
# SysV init works: 01first, 02second, etc. see run-parsts(8) for details
runparts /etc/start.d
# |-- S03keyboard-setup
# |-- S17kbd
# `- S18console-setup
# Virtual consoles to start getty on. Runlevels, speed & $TERM optional
# TTYs are also services, sort of, but they are guaranteed to start at
# the very end of the boot sequence. Finit comes with a built-in getty.
tty [12345] /dev/tty1 115200 vt100
tty [2345] /dev/tty2 38400 linux
tty [2345] /dev/tty3 38400 linux
+14
View File
@@ -0,0 +1,14 @@
#!/bin/sh
exec tail -n +3 $0
# This file provides an easy way to add custom menu entries. Simply type the
# menu entries you want to add after this comment. Be careful not to change
# the 'exec tail' line above.
menuentry '$MENU with Finit' --class $TYPE --class gnu-linux --class gnu --class os --user {
insmod gzio
insmod part_msdos
insmod ext2
search --no-floppy --fs-uuid --set=root $BOOT
linux /vmlinuz root=UUID=$ROOT ro quiet init=/sbin/finit
initrd /initrd.img
}
+55
View File
@@ -0,0 +1,55 @@
#!/bin/sh
SYMLINKS="start.d/*"
FILES="finit.conf"
if [ "x`id -u`" != "x0" ]; then
echo
echo "=> Unfortunately this script must run as root (sudo) <="
echo
exit 1
fi
# Adjust base directory
grep -q Debian os-release 2>/dev/null
if [ $? -eq 0 ]; then
cd ../..
elif [ ! -e finit.c ]; then
echo "Please run this script from the Finit base directory."
exit 1
fi
echo "Install Finit on Debian 8 (jessie)"
echo "========================================================================"
echo "/sbin/finit - PID 1"
echo "/lib/finit/plugins/* - All enabled Finit plugins"
echo "/etc/finit.conf - Instead of units or /etc/init.d Finit can have"
echo " one config for your system. Or you can split"
echo " it in service(s) per file in /etc/finit.d/"
echo "/etc/start.d/ - Simple Debian setup scripts run with run-parts(8)"
echo "/etc/grub.d/40_custom - Add menu entry to the Grub boot loader"
echo
read -p "Do you want to continue (y/N)? " yorn
echo
if [ "x$yorn" = "xy" -o "x$yorn" = "xY" ]; then
echo "Installing Finit files ..."
make install
cd `dirname $0`
mkdir -p /etc/start.d
for file in $FILES; do
install -vbD $file /etc/$file
done
for link in $SYMLINKS; do
cp -va $link /etc/$link
done
echo "Setting up a GRUB boot entry ..."
MENU=`grep gnu-linux /boot/grub/grub.cfg |head -1 |sed "s/menuentry '\([^']*\).*/\1/"`
TYPE=`grep gnu-linux /boot/grub/grub.cfg |head -1 |sed "s/.*' --class \([a-z]*\).*/\1/"`
BOOT=`grep set=root /boot/grub/grub.cfg |head -1 |sed 's/.* \([a-f0-9]*-[a-f0-9]*-[a-f0-9]*-[a-f0-9]*-[a-f0-9]*\).*/\1/'`
ROOT=`grep root=UUID /boot/grub/grub.cfg |head -1 |sed 's/.*UUID=\([a-f0-9]*-[a-f0-9]*-[a-f0-9]*-[a-f0-9]*-[a-f0-9]*\).*/\1/'`
cat grub.d/40_custom | sed "s,\$BOOT,$BOOT,;s,\$ROOT,$ROOT,;s,\$TYPE,$TYPE,;s,\$MENU,$MENU," >/etc/grub.d/40_custom
update-grub
else
echo "Aborting install."
fi
+8
View File
@@ -0,0 +1,8 @@
PRETTY_NAME="Debian GNU/Linux 8 (jessie)"
NAME="Debian GNU/Linux"
VERSION_ID="8"
VERSION="8 (jessie)"
ID=debian
HOME_URL="http://www.debian.org/"
SUPPORT_URL="http://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"
+1
View File
@@ -0,0 +1 @@
../init.d/keyboard-setup
+1
View File
@@ -0,0 +1 @@
../init.d/kbd
+1
View File
@@ -0,0 +1 @@
../init.d/console-setup
+65
View File
@@ -0,0 +1,65 @@
#!/bin/sh
### BEGIN INIT INFO
# Provides: keyboard-setup
# Required-Start: mountkernfs
# Required-Stop:
# Should-Start: keymap udev
# X-Start-Before: checkroot
# Default-Start: S
# Default-Stop:
# X-Interactive: true
# Short-Description: Set preliminary keymap
# Description: Set the console keyboard as early as possible
# so during the file systems checks the administrator
# can interact. At this stage of the boot process
# only the ASCII symbols are supported.
### END INIT INFO
set -e
# This script is not used by keyboard-configuration. It is used
# jointly by console-setup and console-setup-mini
test -f /bin/setupcon || exit 0
if [ -f /lib/lsb/init-functions ]; then
. /lib/lsb/init-functions
else
log_action_begin_msg () {
echo -n "$@... "
}
log_action_end_msg () {
if [ "$1" -eq 0 ]; then
echo done.
else
echo failed.
fi
}
fi
case "$1" in
stop)
# keyboard-setup isn't a daemon
;;
start|force-reload|restart|reload)
case `readlink /proc/self/fd/2` in
/dev/tty[0-9]*|/dev/vc/[0-9]*|/dev/console)
log_action_begin_msg "Setting preliminary keymap"
if setupcon -k; then
log_action_end_msg 0
else
log_action_end_msg $?
fi
;;
*)
exit 0
;;
esac
;;
*)
echo 'Usage: /etc/init.d/keyboard-setup {start|reload|restart|force-reload|stop}'
exit 1
;;
esac
+81
View File
@@ -0,0 +1,81 @@
#!/bin/sh
### BEGIN INIT INFO
# Provides: acpid
# Required-Start: $remote_fs $syslog
# Required-Stop: $remote_fs $syslog
# X-Start-Before: kdm gdm xdm hal
# X-Stop-After: kdm gdm xdm hal
# Default-Start: 2 3 4 5
# Default-Stop:
# Short-Description: Start the Advanced Configuration and Power Interface daemon
# Description: Provide a socket for X11, hald and others to multiplex
# kernel ACPI events.
### END INIT INFO
set -e
ACPID="/usr/sbin/acpid"
DEFAULTS="/etc/default/acpid"
# Check for daemon presence
[ -x "$ACPID" ] || exit 0
OPTIONS=""
MODULES=""
# Include acpid defaults if available
[ -r "$DEFAULTS" ] && . "$DEFAULTS"
# Get lsb functions
. /lib/lsb/init-functions
# As the name says. If the kernel supports modules, it'll try to load
# the ones listed in "MODULES".
load_modules() {
[ -f /proc/modules ] || return 0
if [ "$MODULES" = "all" ]; then
MODULES="$(sed -rn 's#^(/lib/modules/[^/]+/)?kernel/(drivers|ubuntu)/acpi/([^/]+/)*(.*)\.ko:.*#\4#p' "/lib/modules/$(uname -r)/modules.dep")"
fi
if [ -z "$MODULES" ]; then
return
fi
log_begin_msg "Loading ACPI kernel modules..."
# work around a bug in initramfs which leaks this env var Launchpad #291619
# and a bug in modprobe --all --quiet which doesn't load all modules and
# exits with non-zero exit status Debian #504088
unset MODPROBE_OPTIONS
modprobe --all --use-blacklist $MODULES 2>/dev/null
log_end_msg $?
}
case "$1" in
start)
load_modules || true
log_begin_msg "Starting ACPI services..."
start-stop-daemon --start --quiet --oknodo --exec "$ACPID" -- $OPTIONS
log_end_msg $?
;;
stop)
log_begin_msg "Stopping ACPI services..."
start-stop-daemon --stop --quiet --oknodo --retry 2 --exec "$ACPID"
log_end_msg $?
;;
restart)
$0 stop
sleep 1
$0 start
;;
reload|force-reload)
log_begin_msg "Reloading ACPI services..."
start-stop-daemon --stop --signal 1 --exec "$ACPID"
log_end_msg $?
;;
status)
status_of_proc "$ACPID" acpid
;;
*)
log_success_msg "Usage: /etc/init.d/acpid {start|stop|restart|reload|force-reload|status}"
exit 1
esac
+259
View File
@@ -0,0 +1,259 @@
#!/bin/sh
### BEGIN INIT INFO
# Provides: kbd
# Required-Start: $remote_fs
# Required-Stop:
# Default-Start: S
# Default-Stop:
# X-Interactive: true
# Description: Set console screen modes and fonts
# Short-Description: Prepare console
### END INIT INFO
# This is the boot script for the `kbd' package.
# It loads parameters from /etc/kbd/config and maybe loads
# default font and map.
# (c) 1997 Yann Dirson
PKG=kbd
if [ -r /etc/$PKG/config ]; then
. /etc/$PKG/config
fi
if [ -d /etc/$PKG/config.d ]; then
for i in `run-parts --list /etc/$PKG/config.d `; do
. $i
done
fi
# do some magic with the variables for compatibility with the config
# file of console-tools
for vc in '' `set | grep "^.*_vc[0-9][0-9]*=" | sed 's/^.*\(_vc[0-9][0-9]*\)=.*/\1/'`
do
eval [ '"'\${SCREEN_FONT$vc}'"' ] && eval CONSOLE_FONT$vc=\${CONSOLE_FONT$vc:-\${SCREEN_FONT$vc}}
eval [ '"'\${SCREEN_FONT_MAP$vc}'"' ] && eval FONT_MAP$vc=\${FONT_MAP$vc:-\${SCREEN_FONT_MAP$vc}}
eval [ '"'\${APP_CHARSET_MAP$vc}'"' ] && eval CONSOLE_MAP$vc=\${CONSOLE_MAP$vc:-\${APP_CHARSET_MAP$vc}}
done
. /lib/lsb/init-functions
PATH=/sbin:/bin:/usr/sbin:/usr/bin
SETFONT_OPT="-v"
if which setupcon >/dev/null
then
HAVE_SETUPCON=yes
fi
# set DEVICE_PREFIX depending on devfs/udev
if [ -d /dev/vc ]; then
DEVICE_PREFIX="/dev/vc/"
else
DEVICE_PREFIX="/dev/tty"
fi
# determine the system charmap
ENV_FILE=''
[ -r /etc/environment ] && ENV_FILE="/etc/environment"
[ -r /etc/default/locale ] && ENV_FILE="/etc/default/locale"
[ "$ENV_FILE" ] && CHARMAP=$(set -a && . "$ENV_FILE" && locale charmap)
if [ "$CHARMAP" = "UTF-8" -a -z "$CONSOLE_MAP" ]
then
UNICODE_MODE=yes
fi
reset_vga_palette ()
{
if [ -f /proc/fb ]; then
# They have a framebuffer device.
# That means we have work to do...
echo -n "]R"
fi
}
unicode_start_stop ()
{
vc=$1
if [ -n "$UNICODE_MODE" -a -z "`eval echo \\$CONSOLE_MAP_vc$vc`" ]; then
action=unicode_start
else
action=unicode_stop
fi
if [ "${CONSOLE_FONT}" ]; then
$action "${CONSOLE_FONT}" < ${DEVICE_PREFIX}$vc > ${DEVICE_PREFIX}$vc 2> /dev/null || true
else
$action < ${DEVICE_PREFIX}$vc > ${DEVICE_PREFIX}$vc 2> /dev/null || true
fi
}
setup ()
{
# be sure the main program is installed
which setfont >/dev/null || return
VT="no"
# If we can't access the console, quit
CONSOLE_TYPE=`fgconsole 2>/dev/null` || return
if [ ! $CONSOLE_TYPE = "serial" ]; then
readlink /proc/self/fd/0 | grep -q -e /dev/vc -e '/dev/tty[^p]' -e /dev/console
if [ $? -eq 0 ]; then
VT="yes"
reset_vga_palette
fi
fi
[ $VT = "no" ] && return
# start vcstime
if [ "${DO_VCSTIME}" = "yes" ] && which vcstime >/dev/null; then
[ "$VERBOSE" != "no" ] && log_action_begin_msg "Starting clock on text console"
vcstime &
[ "$VERBOSE" != "no" ] && log_action_end_msg 0
fi
if [ -d /etc/init ] && which initctl >/dev/null; then
# Upstart
LIST_CONSOLES=`cd /etc/init; find -name 'tty*.conf' -printf '%f ' | sed -e 's/[^0-9 ]//g'`
else
# traditional SysV init
LIST_CONSOLES=`sed -e '/^ *#/d' /etc/inittab | grep -e '\<tty[0-9]*\>' | awk -F: '{printf "%s ", $1}'`
fi
# Global default font+map
if [ -z "${HAVE_SETUPCON}" -a "${CONSOLE_FONT}" ]; then
[ "$VERBOSE" != "no" ] && log_action_begin_msg "Setting up general console font"
sfm="${FONT_MAP}" && [ "$sfm" ] && sfm="-u $sfm"
acm="${CONSOLE_MAP}" && [ "$acm" ] && acm="-m $acm"
# Set for the first 6 VCs (as they are allocated in /etc/inittab)
for vc in $LIST_CONSOLES
do
if ! ( unicode_start_stop $vc \
&& setfont -C ${DEVICE_PREFIX}$vc ${SETFONT_OPT} $sfm ${CONSOLE_FONT} $acm )
then
[ "$VERBOSE" != "no" ] && log_action_end_msg 1
break
fi
done
[ "$VERBOSE" != "no" ] && log_action_end_msg 0
fi
# Default to Unicode mode for new VTs?
if [ -f /sys/module/vt/parameters/default_utf8 ]; then
if [ -n "$UNICODE_MODE" ]; then
echo 1
else
echo 0
fi > /sys/module/vt/parameters/default_utf8
fi
# Per-VC font+sfm
PERVC_FONTS="`set | grep "^CONSOLE_FONT_vc[0-9]*=" | tr -d \' `"
if [ -z "${HAVE_SETUPCON}" -a "${PERVC_FONTS}" ]; then
[ "$VERBOSE" != "no" ] && log_action_begin_msg "Setting up per-VC fonts"
for font in ${PERVC_FONTS}
do
# extract VC and FONTNAME info from variable setting
vc=`echo $font | cut -b16- | cut -d= -f1`
eval font=\$CONSOLE_FONT_vc$vc
# eventually find an associated SFM
eval sfm=\${FONT_MAP_vc${vc}}
[ "$sfm" ] && sfm="-u $sfm"
if ! ( unicode_start_stop $vc \
&& setfont -C ${DEVICE_PREFIX}$vc ${SETFONT_OPT} $sfm $font )
then
[ "$VERBOSE" != "no" ] && log_action_end_msg 1
break
fi
done
[ "$VERBOSE" != "no" ] && log_action_end_msg 0
fi
# Per-VC ACMs
PERVC_ACMS="`set | grep "^CONSOLE_MAP_vc[0-9]*=" | tr -d \' `"
if [ -z "${HAVE_SETUPCON}" -a "${PERVC_ACMS}" ]; then
[ "$VERBOSE" != "no" ] && log_action_begin_msg "Setting up per-VC ACM's"
for acm in ${PERVC_ACMS}
do
# extract VC and ACM_FONTNAME info from variable setting
vc=`echo $acm | cut -b15- | cut -d= -f1`
eval acm=\$CONSOLE_MAP_vc$vc
if ! setfont -C "${DEVICE_PREFIX}$vc" ${SETFONT_OPT} -m "$acm"; then
[ "$VERBOSE" != "no" ] && log_action_end_msg 1
break
fi
done
[ "$VERBOSE" != "no" ] && log_action_end_msg 0
fi
# screensaver stuff
setterm_args=""
if [ "$BLANK_TIME" ]; then
setterm_args="$setterm_args -blank $BLANK_TIME"
fi
if [ "$BLANK_DPMS" ]; then
setterm_args="$setterm_args -powersave $BLANK_DPMS"
fi
if [ "$POWERDOWN_TIME" ]; then
setterm_args="$setterm_args -powerdown $POWERDOWN_TIME"
fi
if [ "$setterm_args" ]; then
setterm $setterm_args
fi
# Keyboard rate and delay
KBDRATE_ARGS=""
if [ -n "$KEYBOARD_RATE" ]; then
KBDRATE_ARGS="-r $KEYBOARD_RATE"
fi
if [ -n "$KEYBOARD_DELAY" ]; then
KBDRATE_ARGS="$KBDRATE_ARGS -d $KEYBOARD_DELAY"
fi
if [ -n "$KBDRATE_ARGS" ]; then
[ "$VERBOSE" != "no" ] && log_action_begin_msg "Setting keyboard rate and delay"
kbdrate -s $KBDRATE_ARGS
[ "$VERBOSE" != "no" ] && log_action_end_msg 0
fi
# Inform gpm if present, of potential changes.
if [ -f /var/run/gpm.pid ]; then
kill -s WINCH `cat /var/run/gpm.pid` 2> /dev/null
fi
# Allow user to remap keys on the console
if [ -z "${HAVE_SETUPCON}" -a -r /etc/$PKG/remap ]; then
dumpkeys < ${DEVICE_PREFIX}1 | sed -f /etc/$PKG/remap | loadkeys --quiet
fi
# Set LEDS here
if [ -n "$LEDS" ]; then
for i in $LIST_CONSOLES
do
setleds -D $LEDS < $DEVICE_PREFIX$i
done
fi
}
case "$1" in
start|reload|restart|force-reload)
if [ -n "$HAVE_SETUPCON" ]
then
log_action_msg "Setting console screen modes"
else
log_action_msg "Setting console screen modes and fonts"
fi
setup
[ -z "$HAVE_SETUPCON" ] || log_action_msg "Skipping font and keymap setup (handled by console-setup)"
;;
stop)
;;
*)
setup
;;
esac
:
+7 -2
View File
@@ -1,7 +1,12 @@
#!/bin/sh #!/bin/sh
# Alternative boot method for other distributions than Debian 6.0 # Alternative boot method for other distributions than Debian 6.0
# Place this file in a /etc/finit.d/ directory. At boot finit will # Place this file in a /etc/start.d/ directory and add the following
# run all files, using its built-in run_parts(), in that directory. # line to /etc/finit.conf:
#
# runparts /etc/start.d
#
# At boot finit will run all files, using its built-in run_parts(),
# in that directory.
# #
# Here we chain load Debian /etc/rcS.d and /etc/rc2.d directories # Here we chain load Debian /etc/rcS.d and /etc/rc2.d directories
# in sequence using the standard run-parts tool. # in sequence using the standard run-parts tool.
+53
View File
@@ -0,0 +1,53 @@
Bootstrap
=========
1. Populate `/dev`
2. Parse `/etc/finit.conf`
3. Load all `.so` plugins
4. Remount/Pivot `/` to get R+W
5. Call 1st level hooks, `HOOK_ROOTFS_UP`
6. Mount `/etc/fstab` and swap, if available
7. Cleanup stale files from `/tmp/*` et al
8. Enable SysV init signals
9. Call 2nd level hooks, `HOOK_BASEFS_UP`
10. Start all 'S' runlevel tasks and services
11. Load kernel params from `/etc/sysctl.d/*.conf`, `/etc/sysctl.conf`
et al. (Supports all locations that SysV init does.)
12. Set hostname and bring up loopback interface
13. Call `network` script, if set in `/etc/finit.conf`
14. Call 3rd level hooks, `HOOK_NETWORK_UP`
15. Switch to the configured runlevel from `/etc/finit.conf`, default 2.
At every runlevel change all `*.conf` files in `/etc/finit.d/` are
(re)loaded and new services, tasks, and blocking run commands are
started. Provided they are allowed in the new runlevel and all of
their conditions, if any, are set.
16. Call 4th level hooks, `HOOK_SVC_UP`
17. If `runparts <DIR>` is set, [run-parts(8)][] is called on `<DIR>`
18. Call `/etc/rc.local`, if it exists and is an executable shell script
19. Call 5th level (last) hooks, `HOOK_SYSTEM_UP`
20. Start TTYs defined in `/etc/finit.conf`, or rescue on `/dev/console`
In (10) and (15) tasks and services defined in `/etc/finit.conf` are
started. Remember, all `service` and `task` stanzas are started in
parallel and `run` in sequence, and in the order listed. Hence, to
emulate a SysV `/etc/init.d/rcS` one could write a long file with only
`run` statements.
Notice the five hook points that are called at various point in the
bootstrap process. This is where plugins can extend the boot in any way
they please.
For instance, at `HOOK_BASEFS_UP` a plugin could read an XML file from a
USB stick, convert/copy its contents to the system's `/etc/` directory,
well before all 'S' runlevel tasks are started. This could be used with
system images that are created read-only and all configuration is stored
on external media.
[run-parts(8)]: http://manpages.debian.org/cgi-bin/man.cgi?query=run-parts
<!--
-- Local Variables:
-- mode: markdown
-- End:
-->
+99
View File
@@ -0,0 +1,99 @@
Building
========
Finit comes with a traditional configure script to control features and
optional plugins to enable. It does however depend on two external
libraries that provide some frog DNA needed:
- [libuEv][]
- [libite][] (-lite)
Like most free/open source software that uses `configure` they deafult
to install to `/usr/local`. However, some Linux distributions do no
longer search that path for installed software, e.g. Fedora and Alpine
Linux. To get finit's configure script to find its dependencies you
have to help the `pkg-config` tool a bit if you do not change the
default prefix path:
PKG_CONFIG_LIBDIR=/usr/local/lib/pkgconfig ./configure
Below are a few of the main switches to
configure:
* `--disable-inetd`: Disable the built-in inetd server.
* `--enable-embedded`: Target finit for BusyBox getty and mdev instead
of a standard Linux distribution with GNU tools and udev.
* `--enable-rw-rootfs`: Most desktop and server systems boot with the
root file stystem read-only. With this setting Finit will remount it
as read-write early at boot so the `bootmisc.so` plugin can run.
Usually not needed on embedded systems.
* `--enable-static`: Build Finit statically. The plugins will be
built-ins (.o files) and all external libraries, except the C library
will be linked statically.
* `--enable-alsa-utils`: Enable the optional `alsa-utils.so` sound plugin.
* `--enable-dbus`: Enable the optional D-Bus `dbus.so` plugin.
* `--enable-lost`: Enable noisy example plugin for `HOOK_SVC_LOST`.
* `--enable-resolvconf`: Enable the `resolvconf.so` optional plugin.
* `--enable-x11-common`: Enable the optional X Window `x11-common.so` plugin.
For more configure flags, see <kbd>./configure --help</kbd>
**Example**
First, unpack the archive:
```shell
$ tar xf finit-3.0.tar.xz
$ cd finit-3.0/
```
Then configure, build and install:
```shell
$ ./configure --enable-embedded --enable-rw-rootfs --enable-inetd-echo-plugin \
--enable-inetd-chargen-plugin --enable-inetd-daytime-plugin \
--enable-inetd-discard-plugin --enable-inetd-time-plugin \
--with-heading="Alpine Linux 3.4" --with-hostname=alpine
$ make
.
.
.
$ DESTDIR=/tmp/finit make install
```
In this example the [finit-3.0.tar.xz][1] archive is unpacked to the
user's home directory, configured, built and installed to a temporary
staging directory. The environment variable `DESTDIR` controls the
destination directory when installing, very useful for building binary
standalone packages.
To target an embedded Linux system, usally a system that use BusyBox
tools instead of udev & C:o, add <kbd>--enable-embedded</kbd> to the
configure command above. This enables `mdev` instead of `udev` and the
BusyBox `getty` syntax. Remember to also change the Linux config to:
CONFIG_UEVENT_HELPER_PATH="/sbin/mdev"
**Note:** If you run into problems starting Finit, take a look at
`finit.c`. One of the most common problems is a custom Linux kernel
build that lack `CONFIG_DEVTMPFS`. Another is too much cruft in the
system `/etc/fstab`.
[1]: ftp://troglobit.com/finit/finit-3.0.tar.xz
[libuEv]: https://github.com/troglobit/libuev
[libite]: https://github.com/troglobit/libite
<!--
-- Local Variables:
-- mode: markdown
-- End:
-->
+162
View File
@@ -0,0 +1,162 @@
Finit Conditions
================
![The service state machine](svc-machine.png "The service state machine")
Table of Contents
-----------------
* [Introduction](#introduction)
* [Triggering](#triggering)
* [Built-in Conditions](#built-in--conditions)
* [Debugging](#debugging)
* [Internals](#internals)
Introduction
------------
In addition to declaring allowed runlevels per service, it is also
possible to declare user-defined conditions as dependencies. Conditions
are specified within angle brackets (<>) in the service stanza.
Multiple conditions may be specified separated by comma. Conditions are
AND'ed during evaluation, i.e. all conditions must be satisfied in order
for a service to run.
**Example:**
```shell
service [2345] <svc/sbin/setupd,svc/sbin/zebra> /sbin/netd -- Network monitor
```
In this example the Network monitor daemon `netd` is not started until
both the `svc/sbin/setupd` *and* `svc/sbin/zebra` conditions are
satisfied. An `svc` condition is satisfied by the corresponding
service's pidfile being created.
Triggering
----------
Conditions are triggered either by plugins or by using the `cond`
command of the `initctl` control tool.
* `initctl cond set your/cond/here`
To set a condition
* `initctl cond clear your/cond/here`
To clear a condition
Conditions retain their current state until the next reconfiguration or
runlevel change. At that point all set conditions transition into the
`flux` state, meaning the condition's state is unknown. (See
[Internals](#internals) for the rationale behind this.) Thus, after a
reconfiguration it is up to the "owner" of the condition to convey the
new (or possibly unchanged) state of it.
Built-in Conditions
-------------------
Finit is distributed with a `pidfile` and `netlink` plugin. If enabled,
the `pidfile` plugin watches `/var/run/` for PID files created by
monitored services, and sets a corresponding condition in the `svc/`
namespace. Similarily, the `netlink` plugin provides basic conditions
for when an interface is brought up/down and when a default route
(gateway) is set.
With the example listed above, finit does not start the `/sbin/netd`
daemon until `setupd` and `zebra` has started *and* created their PID
files. Which they do when they completed their main tasks of setting up
VLANs, bridge, interfaces, etc. When `netd` in turn starts up it
creates the file `/var/run/netd.pid`, and the condition `svc/sbin/netd`
is satisfied. When the file is removed, the condition is cleared.
The full path to the dependency is needed by finit to match the PID file
to a monitored process.
Built-in conditions:
- `svc/<PATH>`
- `net/route/default`
- `net/<IFNAME>/exist`
- `net/<IFNAME>/up`
Note: `up` is administratively up, `IFF_UP`, not link up, `IFF_RUNNING`.
Debugging
---------
If a service is not being started as it should, the problem might be
that one of its conditions is not in the expected state. Use the
command `initctl status` to inspect service status. Services in the
`ready` state are pending a condition.
In that situation, running `initctl cond show` reveals which of the
conditions that are not satisfied. Listed as `off` below.
**Example:**
```shell
~ # initctl cond show
PID Service Status Condition (+ on, ~ flux, - off)
===============================================================================
1419 /sbin/netd on <+svc/sbin/setupd,+svc/sbin/zebra>
0 /sbin/udhcpc off <-net/vlan1/exist>
```
Here we can see that `netd` is allowed to run since both its conditions
are in the `on` state, as indicated by the `+`-prefix. `udhcpc` however
is not allowed to run since `net/vlan1/exist` condition is not satsifed.
As indicated by the `-`-prefix.
To fake interface `vlan1` suddenly appearing, and test what happens to
`udhcpc` we can enable debug mode and assert the condition, like this:
```shell
~ # initctl debug
~ # initctl cond set net/vlan1/exist
```
Then watch the console for the debug messages and then check the output
from `initctl cond show` again. (The client will likely have failed to
start, but at least the condition is now satisfied.)
Internals
---------
A condition is always in one of three states:
* `on` (+): The condition is asserted.
* `off` (-): The condition is deasserted.
* `flux` (~): The conditions state is unknown.
All conditions that have not explicitly been set are interpreted as
being in the `off` state.
When a reconfiguration is requested, Finit transitions all conditions to
the `flux` state. As a result, services that depend on a condition are
sent `SIGSTOP`. Once the new state of the condition is asserted, the
service receives `SIGCONT`. If the condition is no longer satisfied the
service will then be stopped, otherwise no further action is taken.
This STOP/CONT handling minimizes the number of unnecessary service
restarts that would otherwise occur because a depending service was sent
`SIGHUP` for example.
Therefore, any plugin that supplies Finit with conditions must ensure
that their state is updated after each reconfiguration. This can be
done by binding to the `HOOK_SVC_RECONF` hook. For an example of how
to do this, see `plugins/pidfile.c`.
<!--
-- Local Variables:
-- mode: markdown
-- End:
-->
+219
View File
@@ -0,0 +1,219 @@
Configuration
=============
Table of Contents
-----------------
* [/etc/finit.conf](#etcfinitconf)
* [/etc/finit.d](#etcfinitd)
/etc/finit.conf
---------------
Contrary to most other script based init alternatives (SysV [init][],
[upstart][], [systemd][], [OpenRC][], etc.) Finit relies on its main
configuration file `/etc/finit.conf` and `/etc/finit.d/`.
The command line arguments given in `/etc/finit.conf` to each service
provide a default. A plugin can be used to register a callback to a
service and then modify the behavior to suit the current runlevel and
system configuration.
For instance, before starting a heavily resource intensive service like
IPsec or OpenVPN, a callback can check if the outbound interface is up
and has an IP address, or just check if the service is disabled — much
like what a SysV init start script usually does.
Syntax:
* `check <DEV>`
Run fsck on a file system. Only needed if not listed in `/etc/fstab`,
Finit 3.0 and later check all file systems automatically at boot.
* `module <MODULE>`
Load a kernel module, with optional arguments
* `network <PATH>`
Script or program to bring up networking, with optional arguments
* `rlimit <hard|soft> RESOURCE <LIMIT|infinity>`
Modify the specified resource's hard or soft limit to be the
specifed limit. `RESOURCE` is a lower-case string matching the
constants in `setrlimit(2)` with the `RLIMIT_` prefix
removed. E.g. to select `RLIMIT_CPU`, `RESOURCE` would be
`cpu`. `LIMIT` is an integer whose unit depends on the resource
being modified, see `setrlimit(2)` for more information. The special
limit `infinity` means the there should be no limit on the resource,
i.e. `RLIM_INFINITY` is passed to `setrlimit(2)`.
```shell
# No process is allowed more than 8MB of address space
rlimit hard as 8388608
# Core dumps may be arbitrarily large
rlimit soft core infinity
```
* `runlevel <N>`
N is the runlevel number 1-9, where 6 is reserved for reboot.
Default is 2.
* `run [LVLS] <COND> /path/to/cmd ARGS -- Optional description`
One-shot command to run in sequence when entering a runlevel, with
optional arguments and description. This command is guaranteed to be
completed before running the next command.
* `task [LVLS] <COND> /path/to/cmd ARGS -- Optional description`
One-shot like 'run', but starts in parallel with the next command
* `service [LVLS] <COND> /path/to/daemon ARGS -- Optional description`
Service, or daemon, to be monitored and automatically restarted if it
exits prematurely. Please note that you often need to provide a
`--foreground` or `--no-background` argument to most daemons to
prevent them from forking off a sub-process in the background.
```shell
service [2345] <svc/sbin/zebra> /sbin/ospfd -- OSPF daemon
```
For a detailed description of conditions, and how to debug them,
see the [Finit Conditions](conditions.md) document.
* `inetd service/proto[@iflist] <wait|nowait> [LVLS] /path/to/daemon args`
Launch a daemon when a client initiates a connection on an Internet
port. Available services are listed in the UNIX `/etc/services` file.
Finit can filter access to from a list of interfaces, `@iflist`, per
inetd service as well as listen to custom ports.
```shell
inetd ftp/tcp nowait @root /usr/sbin/uftpd -i -f
inetd tftp/udp wait @root /usr/sbin/uftpd -i -t
```
The following example listens to port 2323 for telnet connections and
only allows clients connecting from `eth0`:
```shell
inetd 2323/tcp@eth0 nowait [2345] /sbin/telnetd -i -F
```
The interface list, `@iflist`, is of the format `@iface,!iface,iface`,
where a single `!` means to deny access. Notice how interfaces are
comma separated with no spaces.
The `inetd` directive can also have ` -- Optional Description`, only
Finit does not output this text on the console when launching inetd
services. Instead this text is sent to syslog and also shown by the
`initctl` tool. More on inetd below.
* `runparts <DIR>`
Call [run-parts(8)][] on `DIR` to run start scripts. All executable
files, or scripts, in the directory are called, in alphabetic order.
It can be beneficial to use `S01name`, `S02othername`, etc. if there
is a dependency order between the scripts. Symlinks to existing
daemons can talso be used, but make sure they daemonize by default.
As the optional `/etc/rc.local` shell script, make sure that all your
services and programs either terminate or start in the background or
you will block Finit.
* `include <CONF>`
Include another configuration file. Absolute path required.
* `tty [LVLS] <DEV> [BAUD] [TERM]`
Start a getty on the given TTY device DEV, in the given runlevels. If
no tty setting is given in `finit.conf` no login is possible. Use the
`service` stanza to start a stand-alone shell for really bare bones
systems.
Finit comes with a lightweight built-in getty, which after it has
opened a TTY and the user has input a username, calls `/bin/login`
like any other getty.
* `console <DEV>`
Use this, along with a matching `tty DEV` line, to mark this TTY as a
special "console" port with with `prctl()`. Useful in use-cases when
all logins except the console must be stopped, e.g. when performing a
flash upgrade on an embedded system.
When running <kbd>make install</kbd> no default `/etc/finit.conf` will
be installed since system requirements differ too much. Try out the
Debian 6.0 example `/usr/share/doc/finit/finit.conf` configuration that
is capable of service monitoring SSH, sysklogd, gdm and a console getty!
Every `run`, `task`, `service`, or `inetd` can also list the privileges
the `/path/to/cmd` should be executed with. Simply prefix the path with
`[@USR[:GRP]]` like this:
```shell
run [2345] @joe:users /usr/bin/logger "Hello world"
```
For multiple instances of the same command, e.g. a DHCP client or
multiple web servers, add `:ID` somewhere between the `run`, `task`,
`service` keyword and the command, like this:
```shell
service :1 [2345] /sbin/httpd -f -h /http -p 80 -- Web server
service :2 [2345] /sbin/httpd -f -h /http -p 8080 -- Old web server
```
Without the `:ID` to the service the latter will overwrite the former
and only the old web server would be started and supervised.
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
------------
Finit supports changes to the overall system configuration at runtime.
For this purpose the (configurable) directory `/etc/finit.d` is used.
Here you can put configuration file snippets, one per service if you
like, which are all sourced automatically by finit at boot when loading
the static configuration from `/etc/finit.conf`. This is the default
behavior, so no include directives are necessary.
To add a new service, simply drop a `.conf` file in `/etc/finit.d` and
run `initctl reload`. (It is also possible to `SIGHUP` to PID 1, or
call `finit q`, but that has been deprecated with the `initctl` tool).
Any service read from this directory is flagged as a dynamic service, so
changes to or removal of `/etc/finit.d/*.conf` files, is detected.
On `initctl reload` the following is checked for all services:
- If a service's `.conf` file has been removed, or its conditions are no
longer satisifed, the service is stopped.
- If the file is modified, or a service it depends on has been reloaded,
the service is reloaded (stopped and started).
- If a new service is added it is automatically started — respecting
runlevels and return values from any callbacks.
For more info on the different states of a service, see the separate
document [Finit Services](service.md).
The `/etc/finit.d` directory was previously the default Finit `runparts`
directory. Finit no longer has a default `runparts`, so make sure to
update your setup, or the finit configuration, accordingly.
**Note:** Configurations read from `/etc/finit.d` are read *after*
initial bootstrap, runlevel S(1). Hence, bootstrap services *must* be
in `/etc/finit.conf`!
[init]: http://en.wikipedia.org/wiki/Init
[upstart]: http://upstart.ubuntu.com/
[systemd]: http://www.freedesktop.org/wiki/Software/systemd/
[openrc]: http://www.gentoo.org/proj/en/base/openrc/
[run-parts(8)]: http://manpages.debian.org/cgi-bin/man.cgi?query=run-parts
<!--
-- Local Variables:
-- mode: markdown
-- End:
-->
+131
View File
@@ -0,0 +1,131 @@
Internet Super Server
=====================
Inetd
-----
A built-in *Internet Super Server* support was added in Finit v1.12 and
v1.13, along with an internal `time` inetd service, RFC 868 (rdate).
The latter is supplied as a plugin to illustrate how simple it is to
extend finit with more internal inetd services. Today more built-in
services are available.
> Please note, not all UNIX daemons are prepared to run as inetd services.
> In the example below `sshd` also need the command line argument `-i`.
The inetd support in finit is quite advanced. Not only does it launch
services on demand, it can do so on custom ports and also filter inbound
traffic using a poor man's [TCP wrappers][]. The syntax is very similar
to the traditional `/etc/inetd.conf`, yet keeping with the style of
Finit:
```shell
# Launch SSH on demand, in runlevels 2-5 as root
inetd ssh/tcp nowait [2345] @root:root /usr/sbin/sshd -i
```
A more advanced example is listed below, please note the *incompatible
syntax change* that was made between Finit v1.12 and v1.13 to support
deny filters:
```shell
# Start sshd if inbound connection on eth0, port 222, or
# inbound on eth1, port 22. Ignore on other interfaces.
inetd 222/tcp@eth0 nowait [2345] /usr/sbin/sshd -i
inetd ssh/tcp@eth1,eth1 nowait [2345] /usr/sbin/sshd -i
```
If `eth0` is your Internet interface you may want to avoid using the
default port. To run ssh on port 222, and all others on port 22:
```shell
inetd 222/tcp@eth0 nowait [2345] /usr/sbin/sshd -i
inetd ssh/tcp@*,!eth0 nowait [2345] /usr/sbin/sshd -i
```
Compared to Finit v1.12 you must *explicitly deny* access from `eth0`!
To protect against looping attacks, the inetd server will refuse UDP
service if the reply port corresponds to any internal service. Similar
to how the FreeBSD inetd operates.
**Internal Services**
Like the original `inetd`, Finit has a few standard services built-in.
They are realized as plugins to provide a simple means of testing the
inetd functionality stand-alone. But this also provides both a useful
network testing/availability, as well as a rudimentary time server for
`rdate` clients.
- echo
- chargen
- daytime
- discard
- time
For security reasons they are all disabled by default and have to be
enabled with both the `configure` script and a special `inetd` stanza in
the `finit.conf` or `finit.d/*.conf` like this:
```shell
inetd echo/udp wait [2345] internal
inetd echo/tcp nowait [2345] internal
inetd chargen/udp wait [2345] internal
inetd chargen/tcp nowait [2345] internal
inetd daytime/udp wait [2345] internal
inetd daytime/tcp nowait [2345] internal
inetd discard/udp wait [2345] internal
inetd discard/tcp nowait [2345] internal
inetd time/udp wait [2345] internal
inetd time/tcp nowait [2345] internal
```
Then call `rdate` from a remote machine (or use localhost):
```shell
rdate -p <IP>
rdate -up <IP>
```
Or `echoping` to reach the echo service:
```shell
echoping -v <IP>
echoping -uv <IP>
```
Or `echoping -d` to reach the discard service:
```shell
echoping -dv <IP>
echoping -duv <IP>
```
Or `echoping -c` to reach the chargen service:
```shell
echoping -cv <IP>
echoping -cuv <IP>
```
If you use `time/udp` you must use the standard rdate implementation and
then call it with `rdate -up` to connect using UDP. Without the `-p`
argument rdate will try to set the system clock. Please note that rdate
has been deprecated by the NTP protocol and this plugin should only be
used for testing or environments where NTP for some reason is blocked.
Also, remember the UNIX year 2038 bug, or in the case of RFC 868 (and
some NTP implementations), year 2036!
**Note:** There is currently no verification that the same port is used
more than once. So a standard `inetd http/tcp` service will clash
with an ssh entry for the same port `inetd 80/tcp` …
[TCP Wrappers]: https://en.wikipedia.org/wiki/TCP_Wrapper
<!--
-- Local Variables:
-- mode: markdown
-- End:
-->
+132
View File
@@ -0,0 +1,132 @@
Hooks & Plugins
===============
Finit can be extended to add general functionality in the form of I/O
monitors, built-in inetd services, or hook plugins.
The following sections detail existing plugins and hook points. For
more information, see the plugins listed below.
Plugins
-------
For your convenience a set of *optional* plugins are available:
* *alsa-utils.so*: Restore and save ALSA sound settings on
startup/shutdown. _Optional plugin._
* *bootmisc.so*: Setup necessary files and system directories for, e.g.,
UTMP (tracks logins at boot). This plugin is central to get a working
system and runs at `HOOK_BASEFS_UP`. The `/var`, `/run`, and `/dev`
file systems must be writable for this plugin to work.
Note: On an embedded system both `/var` and `/run` can be `tmpfs` RAM
disks and `/dev` is usually a `devtmpfs`. This must be defined in the
`/etc/fstab` file and in the Linux kernel config.
* *dbus.so*: Setup and start system message bus, D-Bus, at boot.
_Optional plugin._
* *echo.so*: RFC 862 plugin. Start as inetd service, like time below.
* *chargen.so*: RFC 864 plugin. Start as inetd service, like time below.
* *daytime.so*: RFC 867 plugin. Start as inetd service, like time below.
* *discard.so*: RFC 863 plugin. Start as inetd service, like time below.
* *hwclock.so*: Restore and save system clock from/to RTC on
startup/shutdown.
* *initctl.so*: Extends finit with a traditional `initctl` functionality.
* *lost.so*: Very simple `HOOK_SVC_LOST` example. Logs process ID and
name to syslog. _Optional plugin._
* *netlink.so*: Listens to Linux kernel Netlink events for gateway and
interfaces. These events are then sent to the Finit service monitor
for services that may want to be SIGHUP'ed on new default route or
interfaces going up/down.
* *resolvconf.so*: Setup necessary files for `resolvconf` at startup.
_Optional plugin._
* *time.so*: RFC 868 (rdate) plugin. Start as inetd service. Useful
for testing inetd filtering — BusyBox has an rdate (TCP) client.
* *tty.so*: Watches `/dev`, using inotify, for new device nodes (TTY's)
to start/stop getty consoles on them on demand. Useful when plugging
in a usb2serial converter to login to your embedded device.
* *urandom.so*: Setup random seed at startup.
* *x11-common.so*: Setup necessary files for X-Window. _Optional plugin._
Usually you want to hook into the boot process once, simple hook plugins
like `bootmisc.so` are great for that purpose. They are called at each
hook point in the boot process, useful to insert some pre-bootstrap
mechanisms, like generating configuration files, restoring HW device
state, etc. Available hook points are:
Hooks
-----
### Bootstrap Hooks
* `HOOK_ROOTFS_UP`: When `finit.conf` has been read and `/` has is
mounted — very early
* `HOOK_BASEFS_UP`: All of `/etc/fstab` is mounted, swap is available
and default init signals are setup
* `HOOK_NETWORK_UP`: System bootstrap, runlevel S, has completed and
networking is up (`lo` is up and the `network` script has run)
* `HOOK_SVC_UP`: All services in the active runlevel has been launched
* `HOOK_SYSTEM_UP`: All services *and* everything in `/etc/finit.d`
has been launched
### Runtime Hooks
* `HOOK_SVC_RECONF`: Called when the user has changed something in the
`/etc/finit.d` directory and issued `SIGHUP`. The hook is called when
all modified/removed services have been stopped. When the hook has
completed, Finit continues to start all modified and new services.
* `HOOK_SVC_LOST`: Called when a process is lost. When reconfiguring
services at runtime this hook may be called a lot. However, it may be
a quite useful hook to monitor a system post bootstrap when no, or
few, services are expected to exit. A default plugin `lost.so` is
available in the `plugins/` subdirectory as an example.
**NOTE:** This hook callback gets the lost PID as argument.
* `HOOK_SVC_START`: Like `HOOK_SVC_LOST`, but called when a process is
started. Same caveats apply.
**NOTE:** This hook callback gets the new PID as argument.
* `HOOK_RUNLEVEL_CHANGE`: Called when the user has issued a runlevel
change. The hook is called when services not matching the new
runlevel have been been stopped. When the hook has completed, Finit
continues to start all services in the new runlevel.
### Shutdown Hooks
* `HOOK_SHUTDOWN`: Called at shutdown/reboot, right before all
services are sent `SIGTERM`
Plugins like `initctl.so` and `tty.so` extend finit by acting on events,
they are called I/O plugins and are called from the finit main loop when
`poll()` detects an event. See the source code for `plugins/*.c` for
more help and ideas.
<!--
-- Local Variables:
-- mode: markdown
-- End:
-->
+38
View File
@@ -0,0 +1,38 @@
Finit Services
==============
![The service state machine](svc-machine.png "The service state machine")
State Machine
-------------
A service is bound to a state machine that is in one of six (6) states.
For `run`s and `task`s there is an additional end state called `DONE`,
not shown in the diagram for brevity. Services start in the `HALTED`
state.
The current state depends on the two following conditions:
* `E`: Service enabled. In order for `E` to be satisfied, the service
must be allowed to run in the current runlevel and must not be
blocked. A service may be blocked for several reasons:
- The user has manually stopped the service using `initctl stop JOB`
- The program exits immediately. I.e. keeps crashing (make sure to use
the 'run this service in the foreground' command line option)
- The binary is missing in the filesystem
* `C`: Service conditions are satisfied:
- `on` (+): The condition is asserted.
- `off` (-): The condition is deasserted.
- `flux` (~): The conditions state is unknown.
For a detailed description of conditions, and how to debug them,
see the [Finit Conditions](conditions.md) document.
<!--
-- Local Variables:
-- mode: markdown
-- End:
-->
+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:
-->
Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

+307
View File
@@ -0,0 +1,307 @@
/* Functions for exec'ing processes
*
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
* Copyright (c) 2008-2015 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 */
#include <ctype.h> /* isdigit() */
#include <dirent.h>
#include <stdarg.h>
#include <sys/prctl.h>
#include <sys/wait.h>
#include <lite/lite.h>
#include "finit.h"
#include "helpers.h"
#include "sig.h"
#include "utmp-api.h"
#define NUM_ARGS 16
int getty(char *tty, char *baud, char *term, char *user);
/* Wait for process completion, returns status of waitpid(2) syscall */
int complete(char *cmd, int pid)
{
int status = 0;
if (waitpid(pid, &status, 0) == -1) {
if (errno == EINTR)
_e("Caught unblocked signal waiting for %s, aborting", cmd);
else if (errno == ECHILD)
_e("Caught SIGCHLD waiting for %s, aborting", cmd);
else
_e("Failed starting %s, error %d: %s", cmd, errno, strerror (errno));
return -1;
}
return status;
}
int run(char *cmd)
{
int status, result, i = 0;
char *args[NUM_ARGS + 1], *arg, *backup;
pid_t pid;
/* We must create a copy that is possible to modify. */
backup = arg = strdup(cmd);
if (!arg)
return 1; /* Failed allocating a string to be modified. */
/* Split command line into tokens of an argv[] array. */
args[i++] = strsep(&arg, "\t ");
while (arg && i < NUM_ARGS) {
/* Handle run("su -c \"dbus-daemon --system\" messagebus");
* => "su", "-c", "\"dbus-daemon --system\"", "messagebus" */
if (*arg == '\'' || *arg == '"') {
char *p, delim[2] = " ";
delim[0] = arg[0];
args[i++] = arg++;
strsep(&arg, delim);
p = arg - 1;
*p = *delim;
*arg++ = 0;
} else {
args[i++] = strsep(&arg, "\t ");
}
}
args[i] = NULL;
if (i == NUM_ARGS && args[i]) {
_e("Command too long: %s", cmd);
free(backup);
errno = EOVERFLOW;
return 1;
}
pid = fork();
if (0 == pid) {
FILE *fp;
/* Reset signal handlers that were set by the parent process */
sig_unblock();
setsid();
/* Always redirect stdio for run() */
fp = fopen("/dev/null", "w");
if (fp) {
int fd = fileno(fp);
dup2(fd, STDIN_FILENO);
dup2(fd, STDOUT_FILENO);
dup2(fd, STDERR_FILENO);
}
sig_unblock();
execvp(args[0], args);
_exit(1); /* Only if execv() fails. */
} else if (-1 == pid) {
_pe("%s", args[0]);
free(backup);
return -1;
}
status = complete(args[0], pid);
if (-1 == status) {
free(backup);
return 1;
}
result = WEXITSTATUS(status);
if (WIFEXITED(status)) {
_d("Started %s and ended OK: %d", args[0], result);
} else if (WIFSIGNALED(status)) {
_d("Process %s terminated by signal %d", args[0], WTERMSIG(status));
if (!result)
result = 1; /* Must alert callee that the command did complete successfully.
* This is necessary since not all programs trap signals and
* change their return code accordingly. --Jocke */
}
free(backup);
return result;
}
int run_interactive(char *cmd, char *fmt, ...)
{
int status, oldout = 1, olderr = 2;
char line[LINE_SIZE];
va_list ap;
FILE *fp;
if (!cmd) {
errno = EINVAL;
return 1;
}
if (!silent && fmt) {
va_start(ap, fmt);
vsnprintf(line, sizeof(line), fmt, ap);
va_end(ap);
print_desc("", line);
}
/* Redirect output from cmd to a tempfile */
fp = tempfile();
if (fp && !debug) {
oldout = dup(STDOUT_FILENO);
olderr = dup(STDERR_FILENO);
dup2(fileno(fp), STDOUT_FILENO);
dup2(fileno(fp), STDERR_FILENO);
}
/* Run cmd ... */
status = run(cmd);
/* Restore stderr/stdout */
if (fp && !debug) {
if (oldout >= 0) {
dup2(oldout, STDOUT_FILENO);
close(oldout);
}
if (olderr >= 0) {
dup2(olderr, STDERR_FILENO);
close(olderr);
}
}
if (!silent && fmt)
print_result(status);
/* Dump any results of cmd on stderr after we've printed [ OK ] or [FAIL] */
if (fp && !debug) {
size_t len, written;
rewind(fp);
do {
len = fread(line, 1, sizeof(line), fp);
written = fwrite(line, len, sizeof(char), stderr);
} while (len > 0 && written == len);
}
if (fp)
fclose(fp);
return status;
}
pid_t run_getty(char *tty, char *speed, char *term, int console)
{
pid_t pid;
pid = fork();
if (!pid) {
/* Reset signal handlers that were set by the parent process */
sig_unblock();
setsid();
/* Set INIT_PROCESS UTMP entry */
utmp_set_init(tty, 0);
if (console)
prctl(PR_SET_NAME, "console", 0, 0, 0);
else
prctl(PR_SET_NAME, "finit-getty", 0, 0, 0);
_exit(getty(tty, speed, term, NULL));
}
return pid;
}
int run_parts(char *dir, char *cmd)
{
struct dirent **e;
int i, num;
num = scandir(dir, &e, NULL, alphasort);
if (num < 0) {
_d("No files found in %s, skipping ...", dir);
return -1;
}
for (i = 0; i < num; i++) {
int j = 0;
pid_t pid = 0;
mode_t mode;
char *args[NUM_ARGS];
char *name = e[i]->d_name;
char path[CMD_SIZE];
snprintf(path, sizeof(path), "%s/%s", dir, name);
mode = fmode(path);
if (!S_ISEXEC(mode) || S_ISDIR(mode)) {
_d("Skipping %s ...", path);
continue;
}
/* Fill in args[], starting with full path to executable */
args[j++] = path;
/* If the callee didn't supply a run_parts() argument */
if (!cmd) {
/* Check if S<NUM>service or K<NUM>service notation is used */
_d("Checking if %s is a sysvinit startstop script ...", name);
if (name[0] == 'S' && isdigit(name[1])) {
args[j++] = "start";
} else if (name[0] == 'K' && isdigit(name[1])) {
args[j++] = "stop";
}
} else {
args[j++] = cmd;
}
args[j++] = NULL;
pid = fork();
if (!pid) {
_d("Calling %s ...", path);
sig_unblock();
execv(path, args);
exit(0);
}
complete(path, pid);
}
while (num--)
free(e[num]);
free(e);
return 0;
}
/**
* Local Variables:
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/
+326 -97
View File
@@ -1,7 +1,7 @@
/* Finit - Extremely fast /sbin/init replacement w/ I/O, hook & service plugins /* Finit - Fast /sbin/init replacement w/ I/O, hook & service plugins
* *
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com> * Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
* Copyright (c) 2008-2012 Joachim Nilsson <troglobit@gmail.com> * Copyright (c) 2008-2015 Joachim Nilsson <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -22,61 +22,238 @@
* THE SOFTWARE. * THE SOFTWARE.
*/ */
#include <sys/mount.h> #include "config.h" /* Generated by configure script */
#include <ctype.h> #include <ctype.h>
#include <dirent.h> #include <dirent.h>
#ifdef HAVE_FSTAB_H
#include <fstab.h>
#endif
#include <mntent.h>
#include <sys/mount.h>
#include <sys/stat.h> /* umask(), mkdir() */ #include <sys/stat.h> /* umask(), mkdir() */
#include <sys/wait.h>
#include <lite/lite.h>
#include "finit.h" #include "finit.h"
#include "conf.h"
#include "helpers.h" #include "helpers.h"
#include "private.h" #include "private.h"
#include "plugin.h" #include "plugin.h"
#include "svc.h" #include "service.h"
#include "sig.h" #include "sig.h"
#include "sm.h"
#include "tty.h"
#include "utmp-api.h"
#include "watchdog.h"
int debug = 0; int debug = 0;
int verbose = 1; int quiet = QUIET_MODE; /* Delayed disable of silent mode. */
char *sdown = NULL; int silent = SILENT_MODE; /* Completely silent, including boot */
char *network = NULL; int wdogpid = 0; /* No watchdog by default */
char *username = NULL; int runlevel = 0; /* Bootstrap 'S' */
char *hostname = NULL; int cfglevel = RUNLEVEL; /* Fallback if no configured runlevel */
int prevlevel = -1;
char *sdown = NULL;
char *network = NULL;
char *username = NULL;
char *hostname = NULL;
char *rcsd = FINIT_RCSD;
char *runparts = NULL;
char *console = NULL;
uev_ctx_t *ctx = NULL; /* Main loop context */
static void parse_kernel_cmdline(void) static int banner(void)
{ {
FILE *fp; char buf[42] = INIT_HEADING;
char line[LINE_SIZE]; const char separator[] = "========================================================================";
if ((fp = fopen("/proc/cmdline", "r")) != NULL) { if (silent)
fgets(line, sizeof(line), fp); return 0;
if (strstr(line, "finit_debug") || strstr(line, "--debug")) fprintf(stderr, "\e[2K\e[1m%s %.*s\e[0m\n", buf, 66 - (int)strlen(buf), separator);
debug = 1;
if (!debug && strstr(line, "quiet"))
verbose = 0;
fclose(fp);
}
}
static int run_loop(void)
{
while (1) {
svc_monitor();
io_monitor();
}
return 0; return 0;
} }
int main(int UNUSED(args), char *argv[]) /*
* Check all filesystems in /etc/fstab with a fs_passno > 0
*/
static int fsck(int pass)
{ {
int save;
struct fstab *fs;
if (!setfsent()) {
_pe("Failed opening fstab");
return 1;
}
save = debug;
debug = 0;
while ((fs = getfsent())) {
char cmd[80];
struct stat st;
if (fs->fs_passno != pass)
continue;
errno = 0;
if (stat(fs->fs_spec, &st) || !S_ISBLK(st.st_mode)) {
if (!string_match(fs->fs_spec, "UUID=") && !string_match(fs->fs_spec, "LABEL=")) {
_d("Cannot fsck %s, not a block device: %s", fs->fs_spec, strerror(errno));
continue;
}
}
snprintf(cmd, sizeof(cmd), "/sbin/fsck -a %s", fs->fs_spec);
run_interactive(cmd, "Checking filesystem %.13s", fs->fs_spec);
}
debug = save;
endfsent();
return 0;
}
static void networking(void)
{
FILE *fp;
/* Run user network start script if enabled */
if (network) {
run_interactive(network, "Starting networking: %s", network);
return;
}
/* Debian/Ubuntu/Busybox interfaces file */
fp = fopen("/etc/network/interfaces", "r");
if (fp) {
int i = 0;
char buf[160];
/* Bring up all 'auto' interfaces */
while (fgets(buf, sizeof(buf), fp)) {
char cmd[80];
char *line, *ifname = NULL;
chomp(buf);
line = strip_line(buf);
if (!strncmp(line, "auto", 4))
ifname = &line[5];
if (!strncmp(line, "allow-hotplug", 13))
ifname = &line[14];
if (!ifname)
continue;
snprintf(cmd, 80, "/sbin/ifup %s", ifname);
run_interactive(cmd, "Bringing up interface %s", ifname);
i++;
}
fclose(fp);
if (i)
return;
}
/* Fall back to bring up at least loopback */
ifconfig("lo", "127.0.0.1", "255.0.0.0", 1);
}
/* Requires /proc to be mounted */
static int fismnt(char *dir)
{
FILE *fp;
int found = 0;
struct mntent *mnt;
fp = setmntent("/proc/mounts", "r");
if (!fp)
return 0; /* Dunno, maybe not */
while ((mnt = getmntent(fp))) {
if (!strcmp(mnt->mnt_dir, dir)) {
found = 1;
break;
}
}
endmntent(fp);
return found;
}
/*
* If everything goes south we can use this to give the operator an
* emergency shell to debug the problem -- Finit should not crash!
*/
static void emergency_shell(void)
{
#ifdef EMERGENCY_SHELL
pid_t pid;
pid = fork();
if (pid) {
waitpid(pid, NULL, 0);
fprintf(stderr, "\n=> Embarrassingly, Finit has crashed. Check /dev/kmsg for details.\n");
fprintf(stderr, "=> For more, remove 'quiet' and add '--debug' to the kernel command line.\n\n");
/*
* Become session leader and set controlling TTY
* to enable Ctrl-C and job control in shell.
*/
setsid();
ioctl(STDIN_FILENO, TIOCSCTTY, 1);
execl(_PATH_BSHELL, _PATH_BSHELL, NULL);
}
#endif /* EMERGENCY_SHELL */
}
int main(int argc, char* argv[])
{
char *devfsd;
uev_ctx_t loop;
/*
* finit/init/telinit client tool uses /dev/initctl pipe
* for compatibility but initctl client tool uses socket
*/
if (getpid() != 1)
return client(argc, argv);
/*
* In case of emergency.
*/
emergency_shell();
/*
* Hello world.
*/
banner();
/* /*
* Initial setup of signals, ignore all until we're up. * Initial setup of signals, ignore all until we're up.
*/ */
sig_init(); sig_init();
/*
* Initalize event context.
*/
uev_init(&loop);
ctx = &loop;
/*
* Check file filesystems in /etc/fstab
*/
for (int pass = 1; pass < 10; pass++) {
if (fsck(pass))
break;
}
/* /*
* Mount base file system, kernel is assumed to run devtmpfs for /dev * Mount base file system, kernel is assumed to run devtmpfs for /dev
*/ */
@@ -85,118 +262,170 @@ int main(int UNUSED(args), char *argv[])
mount("none", "/proc", "proc", 0, NULL); mount("none", "/proc", "proc", 0, NULL);
mount("none", "/proc/bus/usb", "usbfs", 0, NULL); mount("none", "/proc/bus/usb", "usbfs", 0, NULL);
mount("none", "/sys", "sysfs", 0, NULL); mount("none", "/sys", "sysfs", 0, NULL);
mkdir("/dev/pts", 0755);
mkdir("/dev/shm", 0755);
mount("none", "/dev/pts", "devpts", 0, "gid=5,mode=620");
mount("none", "/dev/shm", "tmpfs", 0, NULL);
umask(022);
/* /*
* Populate /dev and prepare for runtime events from kernel. * Some non-embedded systems without an initramfs may not have /dev mounted yet
* If they do, check if system has udevadm and perform cleanup from initramfs
*/ */
#if defined(USE_UDEV) if (!fismnt("/dev"))
run_interactive("udevd --daemon", "Populating device tree"); mount("udev", "/dev", "devtmpfs", MS_RELATIME, "size=10%,nr_inodes=61156,mode=755");
#elif defined (MDEV) else if (fexist("/sbin/udevadm"))
run_interactive(MDEV "-s", "Populating device tree"); run_interactive("/sbin/udevadm info --cleanup-db", "Cleaning up udev db");
#endif
/* Some systems use /dev/pts */
makedir("/dev/pts", 0755);
mount("devpts", "/dev/pts", "devpts", 0, "gid=5,mode=620");
makedir("/dev/shm", 0755);
if (!fismnt("/dev/shm"))
mount("shm", "/dev/shm", "tmpfs", 0, NULL);
/*
* New tmpfs based /run for volatile runtime data
* For details, see http://lwn.net/Articles/436012/
*/
if (fisdir("/run") && !fismnt("/run"))
mount("tmpfs", "/run", "tmpfs", MS_NODEV, "mode=0755,size=10%");
umask(022);
/* /*
* Parse kernel parameters * Parse kernel parameters
*/ */
parse_kernel_cmdline(); conf_parse_cmdline();
cls();
echo("finit " VERSION " (built " __DATE__ " " __TIME__ " by " WHOAMI ")");
/* /*
* Parse configuration file * Populate /dev and prepare for runtime events from kernel.
*/ */
parse_finit_conf(FINIT_CONF); if (fexist("/sbin/mdev")) {
/* Embedded Linux systems usually have BusyBox mdev */
if (debug)
touch("/dev/mdev.log");
devfsd = "/sbin/mdev -s";
} else {
if (fexist("/sbin/udevd"))
devfsd = "/sbin/udevd --daemon";
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
* features implemented by plugins.
*/
plugin_init(&loop, PLUGIN_PATH);
/*
* Parse /etc/finit.conf, main configuration file
*/
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);
/* Set default PATH, for uid 0 */
setenv("PATH", _PATH_STDPATH, 1);
/* /*
* Mount filesystems * Mount filesystems
*/ */
_d("Mount filesystems in /etc/fstab ..."); #ifdef REMOUNT_ROOTFS
#ifdef REMOUNT_ROOTFS_RW
run("/bin/mount -n -o remount,rw /"); run("/bin/mount -n -o remount,rw /");
#endif #endif
#ifdef SYSROOT #ifdef SYSROOT
run(SYSROOT, "/", NULL, MS_MOVE, NULL); mount(SYSROOT, "/", NULL, MS_MOVE, NULL);
#endif #endif
/* Debian has this little script to copy generated rules while the system was read-only */
if (fexist("/lib/udev/udev-finish"))
run_interactive("/lib/udev/udev-finish", "Finalizing udev");
_d("Root FS up, calling hooks ...");
plugin_run_hooks(HOOK_ROOTFS_UP);
umask(0); umask(0);
run("/bin/mount -na"); if (run_interactive("/bin/mount -na", "Mounting filesystems"))
plugin_run_hooks(HOOK_MOUNT_ERROR);
run("/sbin/swapon -ea"); run("/sbin/swapon -ea");
umask(0022); umask(0022);
/* Cleanup stale files, if any still linger on. */ /* Base FS up, enable standard SysV init signals */
run_interactive("rm -rf /tmp/* /var/run/* /var/lock/*", "Cleanup temporary directories"); sig_setup(&loop);
_d("Base FS up, calling hooks ...");
plugin_run_hooks(HOOK_BASEFS_UP);
/* /*
* Base FS up, enable standard SysV init signals * Initalize finit state machine and start all bootstrap tasks, no network available!
*/ */
sig_setup(); sm_init(&sm);
sm_step(&sm);
/*
* Load plugins and run first level hooks.
*/
_d("Loading plugins ...");
load_plugins(PLUGIN_PATH);
_d("Running first level hooks ...");
run_hooks(HOOK_BASEFS_UP);
/* /*
* Network stuff * Network stuff
*/ */
networking();
/* Setup kernel specific settings, e.g. allow broadcast ping, etc. */
run("/sbin/sysctl -e -p /etc/sysctl.conf >/dev/null");
/* Set initial hostname. */
set_hostname(hostname);
ifconfig("lo", "127.0.0.1", "255.0.0.0", 1);
if (network)
run_interactive(network, "Starting networking: %s", network);
umask(022); umask(022);
/* /* Hooks that rely on loopback, or basic networking being up. */
* Hooks that rely on loopback, or basic networking being up. plugin_run_hooks(HOOK_NETWORK_UP);
*/
run_hooks(HOOK_NETWORK_UP);
/* /*
* Start service monitor framework * Start all tasks/services in the configured runlevel
*/ */
_d("Starting all static services from %s", FINIT_CONF); service_runlevel(cfglevel);
svc_start_all();
_d("Running svc up hooks ...");
plugin_run_hooks(HOOK_SVC_UP);
/* /*
* Run startup scripts in /etc/finit.d/, if any. * Run startup scripts in the runparts directory, if any.
*/ */
_d("Running startup scripts in /etc/finit.d/ ..."); if (runparts && fisdir(runparts)) {
run_parts(FINIT_RCSD); _d("Running startup scripts in %s ...", runparts);
run_parts(runparts, NULL);
service_reload_dynamic();
}
/* /* Convenient SysV compat for when you just don't care ... */
* Hooks that should run at the very end if (!access(FINIT_RC_LOCAL, X_OK)) {
*/ run_interactive(FINIT_RC_LOCAL, "Calling %s", FINIT_RC_LOCAL);
run_hooks(HOOK_SYSTEM_UP); service_reload_dynamic();
}
/* Start GETTY on console */ /* Hooks that should run at the very end */
_d("Starting getty on console ..."); plugin_run_hooks(HOOK_SYSTEM_UP);
run_getty(GETTY, argv);
/* Start TTYs */
tty_runlevel(runlevel);
/* Enable silent mode, if selected */
if (quiet && !debug)
silent = 1;
/* Start new initctl API responder */
api_init(&loop);
/* /*
* Enter main loop to monior /dev/initctl and services * Enter main loop to monior /dev/initctl and services
*/ */
_d("Entering main loop ..."); return uev_run(&loop, 0);
return run_loop();
} }
/** /**
* Local Variables: * Local Variables:
* version-control: t
* indent-tabs-mode: t * indent-tabs-mode: t
* c-file-style: "linux" * c-file-style: "linux"
* End: * End:
+45 -7
View File
@@ -1,12 +1,50 @@
# Simple Debian finit.conf # Sample finit.conf to demonstrate the syntax
#
user admin
host testbed
# Devices to fsck at boot
check /dev/vda1 check /dev/vda1
# Linux kernel modules to load
module button
module evdev module evdev
module loop module loop
module psmouse module psmouse
user admin
host testbed # Runlevel to start after bootstrap, runlevel 'S'
runlevel 2
# Network bringup script
network service networking start network service networking start
service /sbin/klogd -n -- Kernel logging server
service /sbin/syslogd -n -- Syslog server # Virtual consoles to start getty on
service /usr/sbin/sshd -D -- OpenSSH server tty /dev/tty1
service /usr/sbin/gdm -- GNOME Display Manager tty /dev/tty2
tty /dev/tty3
# Alternative method instead of runparts
#task [S] /etc/init.d/keyboard-setup start -- Setting up preliminary keymap
#task [S] /etc/init.d/acpid start -- Starting ACPI Daemon
#task [S] /etc/init.d/kbd start -- Preparing console
#run [2] /etc/init.d/networking start -- Start networking
# Services to be monitored and respawned as needed
service [2345] /sbin/klogd -n -- Kernel logging server
service [2345] /sbin/syslogd -n -- Syslog server
service [3] /usr/sbin/gdm -- GNOME Display Manager
# Run start scripts from this directory
# runparts /etc/start.d
# Inetd services
inetd time/udp wait [2345] internal -- UNIX rdate service
inetd time/tcp nowait [2345] internal -- UNIX rdate service
inetd ssh@eth0:222/tcp nowait [2345] /usr/sbin/sshd -i -- SSH service
inetd ssh/tcp nowait [2345] /usr/sbin/sshd -i -- SSH service
# For multiple instances of the same service, add :ID somewhere between
# the service/run/task keyword and the command.
service :1 [2345] /sbin/httpd -f -h /http -p 80 -- Web server
service :2 [2345] /sbin/httpd -f -h /http -p 8080 -- Old web server
+58 -36
View File
@@ -1,7 +1,7 @@
/* Finit - Extremely fast /sbin/init replacement w/ I/O, hook & service plugins /* Finit - Fast /sbin/init replacement w/ I/O, hook & service plugins
* *
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com> * Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
* Copyright (c) 2008-2012 Joachim Nilsson <troglobit@gmail.com> * Copyright (c) 2008-2015 Joachim Nilsson <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -27,56 +27,78 @@
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <paths.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <unistd.h> #include <unistd.h>
#include <lite/lite.h>
#include <uev/uev.h>
/* Distribution configuration */ #define CMD_SIZE 256
#define LINE_SIZE 1024
#define BUF_SIZE 4096
#if defined EMBEDDED_SYSTEM /*
# define CONSOLE "/dev/console" * We extend the INIT_CMD_ range for the new initctl tool, Finit only
# define MDEV "/sbin/mdev" * support changing runlevel, reloading the configuration and setenv
# define GETTY "/sbin/getty -L 115200 ttyS0 vt100" * with the old-style /dev/initctl FIFO.
# define LISTEN_INITCTL */
#else /* Debian/Ubuntu based distributions */ #define INIT_SOCKET _PATH_VARRUN "finit.sock"
# define RANDOMSEED "/var/lib/urandom/random-seed" #define INIT_MAGIC 0x03091969
# define CONSOLE "/dev/tty1"
# define GETTY "/sbin/getty -8 38400 tty1"
# define REMOUNT_ROOTFS_RW
# define RUNLEVEL 2
# define LISTEN_INITCTL
# define USE_UDEV
# define USE_MESSAGE_BUS
#endif
#ifndef DEFUSER #define INIT_CMD_START 0
# define DEFUSER "root" #define INIT_CMD_RUNLVL 1
#endif #define INIT_CMD_POWERFAIL 2
#ifndef DEFHOST #define INIT_CMD_POWERFAILNOW 3
# define DEFHOST "noname" #define INIT_CMD_POWEROK 4
#endif #define INIT_CMD_BSD 5
#define INIT_CMD_SETENV 6
#define INIT_CMD_UNSETENV 7
#define CMD_SIZE 256 /* Finit extensions over std SysV */
#define LINE_SIZE 1024 #define INIT_CMD_DEBUG 8 /* Toggle Finit debug */
#define BUF_SIZE 4096 #define INIT_CMD_RELOAD 9 /* Reload *.conf in /etc/finit.d/ */
#define USERNAME_SIZE 16 #define INIT_CMD_START_SVC 10
#define HOSTNAME_SIZE 32 #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_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
extern char *sdown; struct init_request {
extern char *network; int magic; /* Magic number */
extern char *hostname; int cmd; /* What kind of request */
extern char *username; int runlevel; /* Runlevel to change to */
int sleeptime; /* Time between TERM and KILL */
char data[368];
};
/* conf.c */ extern int debug;
void parse_finit_conf(char *file); extern int quiet;
extern int silent;
extern int wdogpid;
extern int runlevel;
extern int cfglevel;
extern int prevlevel;
extern char *rcsd;
extern char *sdown;
extern char *network;
extern char *hostname;
extern char *username;
extern char *runparts;
extern char *console;
extern uev_ctx_t *ctx;
#endif /* FINIT_H_ */ #endif /* FINIT_H_ */
/** /**
* Local Variables: * Local Variables:
* version-control: t
* indent-tabs-mode: t * indent-tabs-mode: t
* c-file-style: "linux" * c-file-style: "linux"
* End: * End:
+347
View File
@@ -0,0 +1,347 @@
/* Initialize and serve a login terminal
*
* 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 <err.h>
#include <errno.h>
#include <paths.h>
#include <signal.h>
#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"
#include "helpers.h"
#include "sig.h"
#include "utmp-api.h"
#ifndef _PATH_LOGIN
#define _PATH_LOGIN "/bin/login"
#endif
#define print(s) (void)write(STDOUT_FILENO, s, strlen(s))
/*
* Read one character from stdin.
*/
static int readch(char *tty)
{
int st;
char ch1;
st = read(STDIN_FILENO, &ch1, 1);
if (st == 0) {
print("\n");
_exit(0);
}
if (st < 0)
errx(1, "getty: %s: read error", tty);
return ch1 & 0xFF;
}
static void stty(int fd, speed_t speed)
{
struct termios term;
tcdrain(fd);
if (tcgetattr(fd, &term))
return;
cfsetispeed(&term, speed);
cfsetospeed(&term, speed);
tcsetattr(fd, TCSAFLUSH, &term);
tcflush(fd, TCIOFLUSH);
/* 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
*/
static void do_parse(char *line, struct utsname *uts, char *tty)
{
char *s, *s0;
s0 = line;
for (s = line; *s != 0; s++) {
if (*s == '\\') {
(void)write(1, s0, s - s0);
s0 = s + 2;
switch (*++s) {
case 'l':
print(tty);
break;
case 'm':
print(uts->machine);
break;
case 'n':
print(uts->nodename);
break;
#ifdef _GNU_SOURCE
case 'o':
print(uts->domainname);
break;
#endif
case 'r':
print(uts->release);
break;
case 's':
print(uts->sysname);
break;
case 'v':
print(uts->version);
break;
case 0:
goto leave;
default:
s0 = s - 1;
}
}
}
leave:
(void)write(1, s0, s - s0);
}
/*
* Parse and display /etc/issue
*/
static void do_issue(char *tty)
{
FILE *fp;
char buf[BUFSIZ] = "Welcome to \\s \\v \\n \\l\n\n";
struct utsname uts;
/*
* Get data about this machine.
*/
uname(&uts);
print("\n");
fp = fopen("/etc/issue", "r");
if (fp) {
while (fgets(buf, sizeof(buf), fp))
do_parse(buf, &uts, tty);
fclose(fp);
} else {
do_parse(buf, &uts, tty);
}
do_parse("\\n login: ", &uts, tty);
}
/*
* Handle the process of a GETTY.
*/
static void do_getty(char *tty, char *name, size_t len)
{
int ch;
char *np;
/*
* Clean up tty name.
*/
if (!strncmp(tty, _PATH_DEV, strlen(_PATH_DEV)))
tty += 5;
/*
* Display prompt.
*/
ch = ' ';
*name = '\0';
while (ch != '\n') {
do_issue(tty);
np = name;
while ((ch = readch(tty)) != '\n') {
if (np < name + len)
*np++ = ch;
}
*np = '\0';
if (*name == '\0')
ch = ' '; /* blank line typed! */
}
name[len - 1] = 0;
}
/* Execute the login(1) command with the current
* username as its argument. It will reply to the
* calling user by typing "Password: "...
*/
static int do_login(char *name)
{
struct stat st;
execl(_PATH_LOGIN, _PATH_LOGIN, name, NULL);
/*
* Failed to exec login, should be impossible. Try a starting a
* fallback shell instead.
*
* Note: Add /etc/securetty handling.
*/
warnx("Failed exec %s, attempting fallback to %s ...", _PATH_LOGIN, _PATH_BSHELL);
if (fstat(0, &st) == 0 && S_ISCHR(st.st_mode))
execl(_PATH_BSHELL, _PATH_BSHELL, NULL);
return 1; /* We shouldn't get here ... */
}
static speed_t do_parse_speed(char *baud)
{
char *ptr;
size_t i;
unsigned long val;
struct { unsigned long val; speed_t speed; } v2s[] = {
{ 0, B0 },
{ 50, B50 },
{ 75, B75 },
{ 110, B110 },
{ 134, B134 },
{ 150, B150 },
{ 200, B200 },
{ 300, B300 },
{ 600, B600 },
{ 1200, B1200 },
{ 1800, B1800 },
{ 2400, B2400 },
{ 4800, B4800 },
{ 9600, B9600 },
{ 19200, B19200 },
{ 38400, B38400 },
{ 57600, B57600 },
{ 115200, B115200 },
{ 230400, B230400 },
{ 460800, B460800 },
{ 500000, B500000 },
{ 576000, B576000 },
{ 921600, B921600 },
{ 1000000, B1000000 },
{ 1152000, B1152000 },
{ 1500000, B1500000 },
{ 2000000, B2000000 },
{ 2500000, B2500000 },
{ 3000000, B3000000 },
{ 3500000, B3500000 },
{ 4000000, B4000000 },
};
errno = 0;
val = strtoul(baud, &ptr, 10);
if (errno || ptr == baud)
return B0;
for (i = 0; i < sizeof(v2s) / sizeof(v2s[0]); i++) {
if (v2s[i].val == val)
return v2s[i].speed;
}
return B0;
}
int getty(char *tty, char *baud, char *UNUSED(term), char *user)
{
int fd;
char name[30];
speed_t speed = B38400;
struct sigaction sa;
if (baud) {
speed = do_parse_speed(baud);
if (speed == B0) {
logit(LOG_CRIT, "TTY %s: Invalid speed %s", tty, baud);
return 1;
}
}
/* Detach from initial controlling TTY */
vhangup();
fd = open(tty, O_RDWR);
if (fd < 0)
err(1, "Failed opening %s", tty);
dup2(fd, STDIN_FILENO);
dup2(fd, STDOUT_FILENO);
dup2(fd, STDERR_FILENO);
if (ioctl(STDIN_FILENO, TIOCSCTTY, 1) < 0)
warn("Failed TIOCSCTTY");
/*
* Don't let QUIT dump core.
*/
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
sa.sa_handler = _exit;
sigaction(SIGQUIT, &sa, NULL);
stty(fd, speed);
close(fd);
utmp_set_login(tty, NULL);
if (!user)
do_getty(tty, name, sizeof(name));
else
strlcpy(name, user, sizeof(name));
return do_login(name);
}
/**
* Local Variables:
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/
+216 -606
View File
@@ -1,7 +1,7 @@
/* Misc. utility functions and C-library extensions for finit and its plugins /* Misc. utility functions for finit and its plugins
* *
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com> * Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
* Copyright (c) 2008-2012 Joachim Nilsson <troglobit@gmail.com> * Copyright (c) 2008-2015 Joachim Nilsson <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -22,328 +22,84 @@
* THE SOFTWARE. * THE SOFTWARE.
*/ */
#include <ctype.h> /* isdigit() */ #include <ctype.h> /* isblank() */
#include <string.h> #include <errno.h>
#include <limits.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/prctl.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <dirent.h>
#include <stdarg.h>
#include <sys/wait.h>
#include <grp.h> #include <grp.h>
#include <pwd.h> #include <pwd.h>
#include <limits.h>
#include <net/if.h>
#include <netinet/in.h>
#include <stdarg.h>
#include <sys/ioctl.h>
#include <lite/lite.h>
#include <lite/conio.h>
#include "finit.h" #include "finit.h"
#include "helpers.h" #include "helpers.h"
#include "private.h" #include "private.h"
#include "sig.h" #include "utmp-api.h"
#define NUM_ARGS 16 int _slup = 0; /* INTERNAL: Is syslog up yet? */
#define NUM_SCRIPTS 128 /* ought to be enough for anyone */
/* char *strip_line(char *line)
* Helpers to replace system() calls {
char *ptr;
/* Trim leading whitespace */
while (*line && isblank(*line))
line++;
/* Strip any comment at end of line */
ptr = line;
while (*ptr && *ptr != '#')
ptr++;
*ptr = 0;
return line;
}
void runlevel_set(int pre, int now)
{
utmp_set_runlevel(pre, now);
}
/**
* runlevel_string - Convert a bit encoded runlevel to .conf syntax
* @levels: Bit encoded runlevels
*
* Returns:
* Pointer to string on the form [2345]
*/ */
char *runlevel_string(int levels)
int makepath(char *path)
{ {
char buf[PATH_MAX]; int i, pos = 1;
char *x = buf; static char lvl[20];
int ret;
if (!path) { memset(lvl, 0, sizeof(lvl));
errno = EINVAL; lvl[0] = '[';
return -1;
}
do { for (i = 0; i < 10; i++) {
do { if (ISSET(levels, i)) {
*x++ = *path++; if (runlevel == i)
} while (*path && *path != '/'); pos = strlcat(lvl, "\e[1m", sizeof(lvl));
*x = 0; if (i == 0)
ret = mkdir(buf, 0777); lvl[pos++] = 'S';
} while (*path && (*path != '/' || *(path + 1))); /* ignore trailing slash */ else
lvl[pos++] = '0' + i;
return ret; if (runlevel == i)
} pos = strlcat(lvl, "\e[0m", sizeof(lvl));
void ifconfig(char *ifname, char *addr, char *mask, int up)
{
struct ifreq ifr;
struct sockaddr_in *a = (struct sockaddr_in *)&ifr.ifr_addr;
int sock;
if ((sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP)) < 0)
return;
memset(&ifr, 0, sizeof (ifr));
strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
ifr.ifr_addr.sa_family = AF_INET;
if (up) {
inet_aton(addr, &a->sin_addr);
ioctl(sock, SIOCSIFADDR, &ifr);
inet_aton(mask, &a->sin_addr);
ioctl(sock, SIOCSIFNETMASK, &ifr);
}
ioctl(sock, SIOCGIFFLAGS, &ifr);
if (up)
ifr.ifr_flags |= IFF_UP;
else
ifr.ifr_flags &= ~IFF_UP;
ioctl(sock, SIOCSIFFLAGS, &ifr);
close(sock);
}
void copyfile(char *src, char *dst, int size)
{
char buffer[BUF_SIZE];
int s, d, n;
/* Size == 0 means copy entire file */
if (size == 0)
size = INT_MAX;
if ((s = open(src, O_RDONLY)) >= 0) {
if ((d = open(dst, O_WRONLY | O_CREAT, 0644)) >= 0) {
do {
int csize = size > BUF_SIZE ? BUF_SIZE : size;
if ((n = read(s, buffer, csize)) > 0)
write(d, buffer, n);
size -= csize;
} while (size > 0 && n == BUF_SIZE);
close(d);
} }
close(s);
}
}
/**
* pidfile_read - Reads a PID value from a pidfile.
* @pidfile: File containing PID, usually in /var/run/<PROC>.pid
*
* This function takes a @pidfile and returns the PID found therein.
*
* Returns:
* On invalid @pidfile -1 and @errno set to %EINVAL, when @pidfile does not exist -1
* and errno set to %ENOENT. When the pidfile is empty or when its contents cannot
* be translated this function returns zero (0), on success this function returns
* a PID value greater than one. PID 1 is reserved for the system init process.
*/
pid_t pidfile_read(const char *pidfile)
{
pid_t pid = 0;
char buf[16];
FILE *fp;
if (!pidfile) {
errno = EINVAL;
return -1;
}
if (!fexist(pidfile))
return -1;
fp = fopen(pidfile, "r");
if (!fp)
return -1;
if (fgets(buf, sizeof(buf), fp)) {
errno = 0;
pid = strtoul(buf, NULL, 0);
if (errno)
pid = 0; /* Failed conversion. */
}
fclose(fp);
return pid;
}
/**
* pidfile_poll - Poll for the existence of a pidfile and return PID
* @cmd: Process name, or command, called to expect a pidfile
* @path: Path to pidfile to poll for
*
* This function polls for the pidfile at @path for at most 5 seconds
* before timing out. If the file is created within that time span the
* file is read and its PID contents returned.
*
* Returns:
* The PID read from @path, or zero on timeout.
*/
pid_t pidfile_poll(char *cmd, const char *path)
{
pid_t pid = 0;
int tries = 0;
/* Timeout = 100 * 50ms = 5s */
while (!fexist(path) && tries++ < 100) {
/* Wait 50ms between retries */
usleep(50000);
} }
if (!fexist(path)) { lvl[pos++] = ']';
_e("Timeout! No PID found for %s, pidfile %s does not exist?", cmd, path); lvl[pos] = 0;
pid = 0;
} else {
pid = pidfile_read(path);
}
return pid; return lvl;
} }
static int print_timestamp(void)
/**
* pid_alive - Check if a given process ID is running
* @pid: Process ID to check for.
*
* Returns:
* %TRUE(1) if pid is alive (/proc/pid exists), otherwise %FALSE(0)
*/
int pid_alive(pid_t pid)
{
char name[24]; /* Enough for max pid_t */
snprintf(name, sizeof(name), "/proc/%d", pid);
return fexist(name);
}
/**
* pid_get_name - Find name of a process
* @pid: PID of process to find.
* @name: Pointer to buffer where to return process name, may be %NULL
* @len: Length in bytes of @name buffer.
*
* If @name is %NULL, or @len is zero the function will return
* a static string. This may be useful to one-off calls.
*
* Returns:
* %NULL on error, otherwise a va
*/
char *pid_get_name(pid_t pid, char *name, size_t len)
{
int ret = 1;
FILE *fp;
char path[32];
static char line[64];
if (!name || len == 0)
name = line;
snprintf(path, sizeof(path), "/proc/%d/status", pid);
if ((fp = fopen(path, "r")) != NULL) {
if (fgets(line, sizeof (line), fp)) {
char *pname = line + 6; /* Skip first part of line --> "Name:\t" */
chomp(pname);
strlcpy(name, pname, len);
ret = 0; /* Found it! */
}
fclose(fp);
}
if (ret)
return NULL;
return name;
}
/**
* procname_set - Change process name, as seen in process listnings
* @name: New name of process
* @args: The process' argv[] vector.
*/
void procname_set(const char *name, char *args[])
{
size_t len = strlen(args[0]) + 1; /* Include terminating '\0' */
prctl(PR_SET_NAME, name, 0, 0, 0);
memset(args[0], 0, len);
strlcpy(args[0], name, len);
}
/**
* procname_kill - Send a signal to a process group by name.
* @name: Name of process to send signal to.
* @signo: Signal to send.
*
* Send a signal to a running process (group). This function searches
* for a given process @name and sends a signal, @signo, to each
* process ID matching that @name.
*
* Returns:
* Number of signals sent, i.e. number of processes who have received the signal.
*/
int procname_kill (const char *name, int signo)
{
int result = 0;
char path[32], line[64];
FILE *fp;
DIR *dir;
struct dirent *entry;
dir = opendir("/proc");
if (!dir || !name) {
errno = EINVAL;
return 0;
}
while ((entry = readdir (dir)) != NULL) {
/* Skip non-process entries in /proc */
if (!isdigit (*entry->d_name))
continue;
snprintf (path, sizeof(path), "/proc/%s/status", entry->d_name);
/* Skip non-readable files (protected?) */
if ((fp = fopen (path, "r")) == NULL)
continue;
if (fgets (line, sizeof (line), fp)) {
char *pname = line + 6; /* Skip first part of line --> "Name:\t" */
if (strncmp(pname, name, strlen(pname) - 1) == 0) {
int error = errno;
if (kill(atoi(entry->d_name), signo)) {
ERROR("Failed signalling(%d) %s: %s!", signo, name, strerror(error));
} else {
result++; /* Track number of processes we deliver the signal to. */
}
}
}
fclose(fp);
}
closedir(dir);
return result;
}
static int print_uptime(void)
{ {
#if defined(CONFIG_PRINTK_TIME) #if defined(CONFIG_PRINTK_TIME)
FILE * uptimefile; FILE * uptimefile;
@@ -364,359 +120,213 @@ static int print_uptime(void)
return 0; return 0;
} }
void print_descr(char *action, char *descr) void print(int action, const char *fmt, ...)
{ {
const char home[] = "\r\e[K"; char buf[80];
size_t len;
va_list ap;
const char success[] = " \e[1m[ OK ]\e[0m\n";
const char failure[] = " \e[7m[FAIL]\e[0m\n";
const char warning[] = " \e[7m[WARN]\e[0m\n";
const char pending[] = " \e[1m[ \\/ ]\e[0m\n";
const char dots[] = " ....................................................................."; const char dots[] = " .....................................................................";
write(STDERR_FILENO, home, strlen(home)); if (silent)
return;
print_uptime(); if (fmt) {
va_start(ap, fmt);
len = vsnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap);
write(STDERR_FILENO, action, strlen(action)); delline();
write(STDERR_FILENO, descr, strlen(descr)); print_timestamp();
write(STDERR_FILENO, dots, 60 - strlen(descr) - strlen(action)); /* pad with dots. */
write(STDERR_FILENO, "\r", 1);
write(STDERR_FILENO, buf, len);
write(STDERR_FILENO, dots, 60 - len); /* pad with dots. */
}
switch (action) {
case -1:
break;
case 0:
write(STDERR_FILENO, success, sizeof(success));
break;
case 1:
write(STDERR_FILENO, failure, sizeof(failure));
break;
case 2:
write(STDERR_FILENO, warning, sizeof(warning));
break;
default:
write(STDERR_FILENO, pending, sizeof(pending));
break;
}
}
void print_desc(char *action, char *desc)
{
print(-1, "%s%s", action ?: "", desc ?: "");
} }
int print_result(int fail) int print_result(int fail)
{ {
if (fail) print(!!fail, NULL);
fprintf(stderr, " \e[7m[FAIL]\e[0m\n");
else
fprintf(stderr, " \e[1m[ OK ]\e[0m\n");
return fail; return fail;
} }
int run(char *cmd) /*
* Log to /dev/kmsg until syslogd has started, then openlog()
* and continue logging as a regular daemon.
*/
void logit(int prio, const char *fmt, ...)
{ {
int status, result, i = 0; va_list ap;
FILE *fp;
char *args[NUM_ARGS + 1], *arg, *backup;
pid_t pid;
/* We must create a copy that is possible to modify. */ va_start(ap, fmt);
backup = arg = strdup(cmd); if (!_slup && !fexist("/dev/log")) {
if (!arg) FILE *fp;
return 1; /* Failed allocating a string to be modified. */
/* Split command line into tokens of an argv[] array. */ fp = fopen("/dev/kmsg", "w");
args[i++] = strsep(&arg, "\t "); if (fp) {
do { if (debug)
/* Handle run("su -c \"dbus-daemon --system\" messagebus"); prio = LOG_ERR;
* => "su", "-c", "\"dbus-daemon --system\"", "messagebus" */
if (*arg == '\'' || *arg == '"') {
char *p, delim[2] = " ";
delim[0] = arg[0]; fprintf(fp, "<%d>finit[1]:", LOG_DAEMON | prio);
args[i++] = arg++; vfprintf(fp, fmt, ap);
strsep(&arg, delim); fclose(fp);
p = arg - 1; } else {
*p = *delim; fprintf(stderr, "Failed opening /dev/kmsg for appending ...\n");
*arg++ = 0; if (debug || prio <= LOG_ERR)
} else { vfprintf(stderr, fmt, ap);
args[i++] = strsep(&arg, "\t "); }
} va_end(ap);
} while (arg && i < NUM_ARGS); return;
args[i] = NULL; }
#if 0
_e("Splitting: '%s' =>", cmd);
for (i = 0; args[i]; i++)
_e("\t%s", args[i]);
#endif
if (i == NUM_ARGS && args[i]) {
_e("Command too long: %s", cmd);
free(backup);
errno = EOVERFLOW;
return 1;
}
fp = fopen("/dev/null", "w"); if (!_slup) {
pid = fork(); openlog("finit", LOG_PID, LOG_DAEMON);
if (0 == pid) { _slup = 1;
int i; }
struct sigaction sa;
/* Reset signal handlers that were set by the parent process */ vsyslog(prio, fmt, ap);
for (i = 1; i < NSIG; i++) va_end(ap);
DFLSIG(sa, i, 0);
/* Redirect stdio if the caller requested so. */
if (fp) {
int fd = fileno(fp);
dup2(fd, STDIN_FILENO);
dup2(fd, STDOUT_FILENO);
dup2(fd, STDERR_FILENO);
}
execvp(args[0], args);
_exit(1); /* Only if execv() fails. */
} else if (-1 == pid) {
_pe("%s", args[0]);
return -1;
}
if (waitpid(pid, &status, 0) == -1) {
if (errno == EINTR)
_e("Caught unblocked signal waiting for %s, aborting.", args[0]);
else if (errno == ECHILD)
_e("Caught SIGCHLD waiting for %s, aborting.", args[0]);
else
_e("Failed starting %s, error %d: %s", args[0], errno, strerror (errno));
if (fp) fclose(fp);
free(backup);
return 1;
}
result = WEXITSTATUS(status);
if (WIFEXITED(status)) {
_d("Started %s and ended OK: %d", args[0], result);
} else if (WIFSIGNALED(status)) {
_d("Process %s terminated by signal %d", args[0], WTERMSIG(status));
if (!result)
result = 1; /* Must alert callee that the command did complete successfully.
* This is necessary since not all programs trap signals and
* change their return code accordingly. --Jocke */
}
if (fp) fclose(fp);
free(backup);
return result;
} }
int run_interactive(char *cmd, char *fmt, ...) int getuser(char *username, char **home)
{
int status, oldout = 1, olderr = 2;
char line[LINE_SIZE];
va_list ap;
FILE *fp = tmpfile();
va_start(ap, fmt);
vsnprintf(line, sizeof(line), fmt, ap);
va_end(ap);
print_descr("", line);
if (fp && !debug) {
oldout = dup(STDOUT_FILENO);
olderr = dup(STDERR_FILENO);
dup2(fileno(fp), STDOUT_FILENO);
dup2(fileno(fp), STDERR_FILENO);
}
status = run(cmd);
if (fp && !debug) {
dup2(oldout, STDOUT_FILENO);
dup2(olderr, STDERR_FILENO);
}
print_result(status);
if (fp && !debug) {
size_t len, written;
rewind(fp);
do {
len = fread(line, 1, sizeof(line), fp);
written = fwrite(line, len, sizeof(char), stderr);
} while (len > 0 && written == len);
fclose(fp);
}
return status;
}
pid_t run_getty(char *cmd, char *argv[])
{
pid_t pid = fork();
if (!pid) {
int i;
char c;
sigset_t nmask;
struct sigaction sa;
/* Detach from initial controlling TTY */
vhangup();
close(2);
close(1);
close(0);
/* Attach TTY to console */
if (open(CONSOLE, O_RDWR) != 0)
exit(1);
sigemptyset(&sa.sa_mask);
sa.sa_handler = SIG_DFL;
sigemptyset(&nmask);
sigaddset(&nmask, SIGCHLD);
sigprocmask(SIG_UNBLOCK, &nmask, NULL);
for (i = 1; i < NSIG; i++)
sigaction(i, &sa, NULL);
dup2(0, STDIN_FILENO);
dup2(0, STDOUT_FILENO);
dup2(0, STDERR_FILENO);
procname_set("console", argv);
while (!fexist(SYNC_SHUTDOWN)) {
static const char msg[] = "\nPlease press Enter to activate this console. ";
if (fexist(SYNC_STOPPED)) {
sleep(1);
continue;
}
i = write(STDERR_FILENO, msg, sizeof(msg) - 1);
while (read(STDIN_FILENO, &c, 1) == 1 && c != '\n')
continue;
if (fexist(SYNC_STOPPED))
continue;
run(cmd);
}
exit(0);
}
return pid;
}
static int cmp(const void *s1, const void *s2)
{
return strcmp(*(char **)s1, *(char **)s2);
}
int run_parts(char *dir, ...)
{
DIR *d;
struct dirent *e;
struct stat st;
char *oldpwd = NULL;
char *ent[NUM_SCRIPTS];
int i, num = 0, argnum = 1;
char *args[NUM_ARGS];
va_list ap;
oldpwd = getcwd (NULL, 0);
if (chdir(dir)) {
if (oldpwd) free(oldpwd);
return -1;
}
if ((d = opendir(dir)) == NULL) {
if (oldpwd) free(oldpwd);
return -1;
}
va_start(ap, dir);
while (argnum < NUM_ARGS && (args[argnum++] = va_arg(ap, char *)));
va_end(ap);
while ((e = readdir(d))) {
if (e->d_type == DT_REG && stat(e->d_name, &st) == 0) {
_d("Found %s/%s ...", dir, e->d_name);
if (st.st_mode & S_IXUSR) {
ent[num++] = strdup(e->d_name);
if (num >= NUM_SCRIPTS)
break;
}
}
}
closedir(d);
if (num == 0) {
if (oldpwd) free(oldpwd);
return 0;
}
qsort(ent, num, sizeof(char *), cmp);
for (i = 0; i < num; i++) {
pid_t pid = 0;
int status;
args[0] = ent[i];
args[1] = NULL;
pid = fork();
if (!pid) {
_d("Calling %s ...", ent[i]);
execv(ent[i], args);
exit(0);
}
waitpid(pid, &status, 0);
free(ent[i]);
}
chdir(oldpwd);
free(oldpwd);
return 0;
}
int getuser(char *username)
{ {
#ifdef ENABLE_STATIC
*home = "/"; /* XXX: Fixme */
return fgetint("/etc/passwd", "x:\n", username);
#else
struct passwd *usr; struct passwd *usr;
if (!username || (usr = getpwnam(username)) == NULL) if (!username || (usr = getpwnam(username)) == NULL)
return -1; return -1;
return usr->pw_uid; *home = usr->pw_dir;
return usr->pw_uid;
#endif
} }
int getgroup(char *group) int getgroup(char *group)
{ {
#ifdef ENABLE_STATIC
return fgetint("/etc/group", "x:\n", group);
#else
struct group *grp; struct group *grp;
if ((grp = getgrnam(group)) == NULL) if ((grp = getgrnam(group)) == NULL)
return -1; return -1;
return grp->gr_gid; return grp->gr_gid;
#endif
} }
/* /* Signal safe sleep ... we get a lot of SIGCHLD at reboot */
* Other convenience functions void do_sleep(unsigned int sec)
*/
void cls(void)
{ {
static const char cls[] = "\e[2J\e[1;1H"; while ((sec = sleep(sec)))
;
if (!debug)
fprintf (stderr, "%s", cls);
} }
void chomp(char *str) void set_hostname(char **hostname)
{
char *x;
if ((x = strchr((str), 0x0a)) != NULL)
*x = 0;
}
void set_hostname(char *hostname)
{ {
FILE *fp; FILE *fp;
_d("Set hostname: %s", hostname); fp = fopen("/etc/hostname", "r");
if ((fp = fopen("/etc/hostname", "r")) != NULL) { if (fp) {
fgets(hostname, HOSTNAME_SIZE, fp); struct stat st;
chomp(hostname);
if (fstat(fileno(fp), &st)) {
fclose(fp);
return;
}
*hostname = realloc(*hostname, st.st_size);
if (!*hostname) {
fclose(fp);
return;
}
fgets(*hostname, st.st_size, fp);
chomp(*hostname);
fclose(fp); fclose(fp);
} }
sethostname(hostname, strlen(hostname)); if (*hostname)
sethostname(*hostname, strlen(*hostname));
} }
#ifndef HAVE_GETFSENT
static lfile_t *fstab = NULL;
int setfsent(void)
{
if (fstab)
lfclose(fstab);
fstab = lfopen("/etc/fstab", " \t\n");
if (!fstab)
return 0;
return 1;
}
struct fstab *getfsent(void)
{
static struct fstab fs;
fs.fs_spec = lftok(fstab);
if (fs.fs_spec == NULL)
return NULL;
fs.fs_file = lftok(fstab);
fs.fs_vfstype = lftok(fstab);
fs.fs_mntops = lftok(fstab);
fs.fs_type = "rw";
fs.fs_freq = atoi(lftok(fstab) ?: "0");
fs.fs_passno = atoi(lftok(fstab) ?: "0");
return &fs;
}
void endfsent(void)
{
if (fstab)
lfclose(fstab);
fstab = NULL;
}
#endif /* HAVE_GETFSENT */
/** /**
* Local Variables: * Local Variables:
* version-control: t
* indent-tabs-mode: t * indent-tabs-mode: t
* c-file-style: "linux" * c-file-style: "linux"
* End: * End:
+49 -53
View File
@@ -1,7 +1,7 @@
/* Misc. utility functions and C-library extensions for finit and its plugins /* Misc. utility functions and C-library extensions for finit and its plugins
* *
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com> * Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
* Copyright (c) 2008-2012 Joachim Nilsson <troglobit@gmail.com> * Copyright (c) 2008-2015 Joachim Nilsson <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -25,79 +25,75 @@
#ifndef FINIT_HELPERS_H_ #ifndef FINIT_HELPERS_H_
#define FINIT_HELPERS_H_ #define FINIT_HELPERS_H_
#include <err.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> /* strerror() */
#include <syslog.h> #include <syslog.h>
#include <sys/types.h>
#define DO_LOG(level, fmt, args...) \ /*
{ \ * Error and debug messages
openlog("finit", LOG_CONS | LOG_PID, LOG_DAEMON); \ *
syslog(LOG_DEBUG, fmt, ##args); \ * Use of logit() is preferred, but these are guaranteed to display on
closelog(); \ * /dev/console as well. Useful for critical errors and early debug.
} */
#define _l(prio, fmt, args...) do { if (_slup) warnx(fmt, ##args); logit(prio, fmt "\n", ##args); } while (0)
#define _m(prio, fmt, args...) do { _l(prio, "%s() - " fmt, __func__, ##args); } while (0)
#define _d(fmt, args...) do { if (debug) { _m(LOG_DEBUG, fmt, ##args); } } while (0)
#define _w(fmt, args...) do { _m(LOG_WARNING, fmt, ##args); } while (0)
#define _e(fmt, args...) do { _m(LOG_ERR, fmt, ##args); } while (0)
#define _pe(fmt, args...) do { _m(LOG_ERR, fmt ". Error %d: %s", ##args, errno, strerror(errno)); } while (0)
#define DEBUG(fmt, args...) DO_LOG(LOG_DEBUG, fmt, ##args) extern int _slup; /* INTERNAL: Is syslog up yet? */
#define ERROR(fmt, args...) DO_LOG(LOG_CRIT, fmt, ##args)
#ifndef touch char *strip_line (char *line);
# define touch(x) mknod((x), S_IFREG|0644, 0)
#endif
#ifndef chardev
# define chardev(x,m,maj,min) mknod((x), S_IFCHR|(m), makedev((maj),(min)))
#endif
#ifndef blkdev
# define blkdev(x,m,maj,min) mknod((x), S_IFBLK|(m), makedev((maj),(min)))
#endif
#ifndef fexist
# define fexist(x) (access(x, F_OK) != -1)
#endif
#ifndef UNUSED void runlevel_set (int pre, int now);
#define UNUSED(x) UNUSED_ ## x __attribute__ ((unused)) char *runlevel_string (int levels);
#endif
#define echo(fmt, args...) do { if (1) { fprintf(stderr, fmt "\n", ##args); } } while (0)
#define _d(fmt, args...) do { if (debug) { fprintf(stderr, "finit:%s() - " fmt "\n", __func__, ##args); } } while (0)
#define _e(fmt, args...) do { fprintf(stderr, "finit:%s() - " fmt "\n", __func__, ##args); } while (0)
#define _pe(fmt, args...) do { fprintf(stderr, "finit:%s() - " fmt ". Error %d: %s\n", __func__, ##args, errno, strerror(errno)); } while (0)
extern int debug;
extern int verbose;
int makepath (char *path);
void ifconfig (char *ifname, char *addr, char *mask, int up);
void copyfile (char *src, char *dst, int size);
pid_t pidfile_read (const char *pidfile);
pid_t pidfile_poll (char *cmd, const char *path);
int pid_alive (pid_t pid); int pid_alive (pid_t pid);
char *pid_get_name (pid_t pid, char *name, size_t len); char *pid_get_name (pid_t pid, char *name, size_t len);
void procname_set (const char *name, char *args[]); void procname_set (char *name, char *args[]);
int procname_kill (const char *name, int signo);
void print_descr (char *action, char *descr); void print (int action, const char *fmt, ...);
void print_desc (char *action, char *desc);
int print_result (int fail); int print_result (int fail);
int start_process (char *cmd, char *args[], int console);
void cls (void);
void chomp (char *str);
int getuser (char *username);
int getgroup (char *group);
void set_hostname (char *hostname);
void logit (int prio, const char *fmt, ...);
int start_process (char *cmd, char *args[], int console);
void do_sleep (unsigned int sec);
int getuser (char *username, char **home);
int getgroup (char *group);
void set_hostname (char **hostname);
int complete (char *cmd, int pid);
int run (char *cmd); int run (char *cmd);
int run_interactive (char *cmd, char *fmt, ...); int run_interactive (char *cmd, char *fmt, ...);
pid_t run_getty (char *cmd, char *argv[]); pid_t run_getty (char *tty, char *speed, char *term, int console);
int run_parts (char *dir, ...); int run_parts (char *dir, char *cmd);
/* strlcpy.c */ #ifndef HAVE_GETFSENT
size_t strlcpy(char *dst, const char *src, size_t siz); struct fstab {
char *fs_spec; /* block device name */
char *fs_file; /* mount point */
char *fs_vfstype; /* file-system type */
char *fs_mntops; /* mount options */
const char *fs_type; /* rw/rq/ro/sw/xx option */
int fs_freq; /* dump frequency, in days */
int fs_passno; /* pass number on parallel dump */
};
int setfsent(void);
void endfsent(void);
struct fstab *getfsent(void);
#endif /* HAVE_GETFSENT */
#endif /* FINIT_HELPERS_H_ */ #endif /* FINIT_HELPERS_H_ */
/** /**
* Local Variables: * Local Variables:
* version-control: t
* indent-tabs-mode: t * indent-tabs-mode: t
* c-file-style: "linux" * c-file-style: "linux"
* End: * End:
Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

+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

+735
View File
@@ -0,0 +1,735 @@
/* Classic inetd services launcher for Finit
*
* Copyright (c) 2015 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 <ifaddrs.h>
#include <net/if.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <uev/uev.h>
#include <lite/lite.h>
#include "finit.h"
#include "inetd.h"
#include "helpers.h"
#include "private.h"
#include "service.h"
#define ENABLE_SOCKOPT(sd, level, opt) \
do { \
int val = 1; \
if (setsockopt(sd, level, opt, &val, sizeof(val)) < 0) \
logit(LOG_CRIT, "Failed enabling %s on %s service", \
#opt, inetd->name); \
} while (0);
/* Peek into SOCK_DGRAM socket to figure out where an inbound packet comes from. */
static int inetd_dgram_peek(int sd, char *ifname)
{
char cmbuf[0x100];
struct msghdr msgh;
struct cmsghdr *cmsg;
memset(&msgh, 0, sizeof(msgh));
msgh.msg_control = cmbuf;
msgh.msg_controllen = sizeof(cmbuf);
if (recvmsg(sd, &msgh, MSG_PEEK) < 0)
return -1;
for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg; cmsg = CMSG_NXTHDR(&msgh,cmsg)) {
struct in_pktinfo *ipi = (struct in_pktinfo *)CMSG_DATA(cmsg);
if (cmsg->cmsg_level != SOL_IP || cmsg->cmsg_type != IP_PKTINFO)
continue;
if_indextoname(ipi->ipi_ifindex, ifname);
return 0;
}
return -1;
}
/* Peek into SOCK_STREAM on accepted client socket to figure out inbound interface */
static int inetd_stream_peek(int sd, char *ifname)
{
struct ifaddrs *ifaddr, *ifa;
struct sockaddr_in sin;
socklen_t len = sizeof(sin);
if (-1 == getsockname(sd, (struct sockaddr *)&sin, &len))
return -1;
if (-1 == getifaddrs(&ifaddr))
return -1;
for (ifa = ifaddr; ifa; ifa = ifa->ifa_next) {
size_t len = sizeof(struct in_addr);
struct sockaddr_in *iin;
if (!ifa->ifa_addr)
continue;
if (ifa->ifa_addr->sa_family != AF_INET)
continue;
iin = (struct sockaddr_in *)ifa->ifa_addr;
if (!memcmp(&sin.sin_addr, &iin->sin_addr, len)) {
strncpy(ifname, ifa->ifa_name, IF_NAMESIZE);
break;
}
}
freeifaddrs(ifaddr);
return 0;
}
static int get_stdin(svc_t *svc)
{
int stdin = svc->inetd.watcher.fd;
char ifname[IF_NAMESIZE] = "UNKNOWN";
if (svc->inetd.type == SOCK_STREAM) {
/* Open new client socket from server socket */
stdin = accept(stdin, NULL, NULL);
if (stdin < 0) {
logit(LOG_CRIT, "Failed accepting inetd service %d/tcp", svc->inetd.port);
return -1;
}
_d("New client socket %d accepted for inetd service %d/tcp", stdin, svc->inetd.port);
inetd_stream_peek(stdin, ifname);
} else { /* SOCK_DGRAM */
inetd_dgram_peek(stdin, ifname);
}
if (!inetd_is_allowed(&svc->inetd, ifname)) {
logit(LOG_INFO, "Service %s on %s:%d is not allowed", svc->inetd.name, ifname, svc->inetd.port);
if (svc->inetd.type == SOCK_STREAM)
close(stdin);
return -1;
}
return stdin;
}
/* Socket callback, looks up correct svc and starts it as an inetd service */
static void socket_cb(uev_t *UNUSED(w), void *arg, int UNUSED(events))
{
svc_t *svc = (svc_t *)arg, *task;
int stdin;
_d("Got event on %s socket ...", svc->cmd);
stdin = get_stdin(svc);
if (stdin < 0) {
logit(LOG_CRIT, "%s: Unable to accept incoming connection", svc->cmd);
return;
}
/*
* Make sure to disable O_NONBLOCK on the descriptor before
* passing it to the inetd service, that's what is expected.
*/
if (fcntl(stdin, F_SETFL, fcntl(stdin, F_GETFL, 0) & ~O_NONBLOCK) < 0) {
logit(LOG_CRIT, "Failed disabling non-blocking on %s socket", svc->cmd);
return;
}
task = svc_new(svc->cmd, svc->inetd.next_id++, SVC_TYPE_INETD_CONN);
if (!task) {
logit(LOG_CRIT, "%s: Unable to allocate service for inetd client",
svc->cmd);
return;
}
if (!svc->inetd.forking) {
svc_busy(svc);
service_step(svc);
}
/* Copy inherited attributes from inetd service's svc */
task->runlevels = svc->runlevels;
/* Only copy the most relevant parts of inetd, in particular we
* must *not* copy the watcher data to the clone! */
task->inetd.svc = svc;
task->inetd.cmd = svc->inetd.cmd;
task->inetd.type = svc->inetd.type;
memcpy(task->cond, svc->cond, sizeof(task->cond));
memcpy(task->username, svc->username, sizeof(task->username));
memcpy(task->group, svc->group, sizeof(task->group));
memcpy(task->args, svc->args, sizeof(task->args));
snprintf(task->desc, sizeof(task->desc), "%s connection", svc->desc);
task->stdin_fd = stdin;
service_step(task);
}
/*
* Refuse service if the request specifies a reply port corresponding to any internal service.
* This is done as a defense against looping attacks; the remote IP address is logged.
* http://www.freebsd.org/cgi/man.cgi?inetd(8)
* https://svnweb.freebsd.org/base/head/usr.sbin/inetd/inetd.c?revision=298909&view=markup#l2094
*/
int inetd_check_loop(struct sockaddr *sa, socklen_t len, char *name)
{
svc_t *svc;
char pname[NI_MAXHOST];
for (svc = svc_inetd_iterator(1); svc; svc = svc_inetd_iterator(0)) {
inetd_t *i = &svc->inetd;
if (!i->builtin || i->type != SOCK_DGRAM)
continue;
if (((const struct sockaddr_in *)sa)->sin_port == i->port) {
getnameinfo(sa, len, pname, sizeof(pname), NULL, 0, NI_NUMERICHOST);
logit(LOG_WARNING, "%s/%s:%s/%s loop request REFUSED from %s", i->name, "UDP", name, "UDP", pname);
return 1;
}
}
return 0;
}
/* Launch Inet socket for service.
* TODO: Add filtering ALLOW/DENY per interface.
*/
static int spawn_socket(inetd_t *inetd)
{
int sd;
socklen_t len = sizeof(struct sockaddr);
struct sockaddr_in s;
if (!inetd->type) {
logit(LOG_CRIT, "Invalid inetd service %s, skipping ...", inetd->name);
return -EINVAL;
}
_d("Spawning server socket for inetd %s, type %s ...", inetd->name, inetd->type == SOCK_STREAM ? "stream" : "dgram");
sd = socket(AF_INET, inetd->type | SOCK_NONBLOCK | SOCK_CLOEXEC, inetd->proto);
if (-1 == sd) {
logit(LOG_CRIT, "Failed opening inetd socket type %d proto %d", inetd->type, inetd->proto);
return -errno;
}
ENABLE_SOCKOPT(sd, SOL_SOCKET, SO_REUSEADDR);
#ifdef SO_REUSEPORT
ENABLE_SOCKOPT(sd, SOL_SOCKET, SO_REUSEPORT);
#endif
memset(&s, 0, sizeof(s));
s.sin_family = AF_INET;
s.sin_addr.s_addr = INADDR_ANY;
s.sin_port = htons(inetd->port);
if (bind(sd, (struct sockaddr *)&s, len) < 0) {
logit(LOG_CRIT, "Failed binding to port %d, maybe another %s server is already running?",
inetd->port, inetd->name);
close(sd);
return -errno;
}
if (inetd->port) {
if (inetd->type == SOCK_STREAM) {
if (-1 == listen(sd, 10)) {
logit(LOG_CRIT, "Failed listening to inetd service %s", inetd->name);
close(sd);
return -errno;
}
} else { /* SOCK_DGRAM */
/* Set extra sockopt to get ifindex from inbound packets */
ENABLE_SOCKOPT(sd, SOL_IP, IP_PKTINFO);
}
}
if (uev_io_init(ctx, &inetd->watcher, socket_cb, inetd->svc, sd, UEV_READ)) {
logit(LOG_CRIT, "Failed setting up inetd watcher for %s", inetd->name);
close(sd);
return -errno;
}
return 0;
}
int inetd_start(inetd_t *inetd)
{
int sd;
char buf[BUFSIZ];
ssize_t len;
sd = inetd->watcher.fd;
if (sd == -1)
return spawn_socket(inetd);
/* Read anything lingering, or clean up socket after failure */
len = recv(sd, buf, sizeof(buf), MSG_DONTWAIT);
if (len > 0)
_d("Read %zd lingering bytes from socket before (re)starting %s ...", len, inetd->svc->cmd);
/* Restore O_NONBLOCK for socket */
if (fcntl(sd, F_SETFL, fcntl(sd, F_GETFL, 0) | O_NONBLOCK)) {
logit(LOG_CRIT, "Cannot safely (re)start %s inetd service", inetd->svc->cmd);
return -errno;
}
_d("Re-starting %s socket watcher ...", inetd->svc->cmd);
uev_io_start(&inetd->watcher);
return 0;
}
void inetd_stop(inetd_t *inetd)
{
if (inetd->watcher.fd != -1) {
_d("Stopping %s socket watcher ...", inetd->svc->cmd);
uev_io_stop(&inetd->watcher);
/* For dgram inetd services we block the parent SVC
* and halt the watcher, so don't close the socket! */
if (!svc_is_busy(inetd->svc)) {
_d("Shutting down inet socket %d ...", inetd->watcher.fd);
if (inetd->type == SOCK_STREAM)
shutdown(inetd->watcher.fd, SHUT_RDWR);
close(inetd->watcher.fd);
inetd->watcher.fd = -1;
}
}
}
static struct servent *fallback_service(char *service, char *proto)
{
int service_num;
static struct servent lfs;
service_num = fgetint("/etc/services", " \n\t", service);
if (service_num > 0) {
lfs.s_name = service;
lfs.s_port = htons(service_num);
lfs.s_proto = NULL;
if (!strcmp("tcp", proto) || !strcmp("udp", proto))
lfs.s_proto = proto;
return &lfs;
}
return NULL;
}
static struct servent *getent_service(char *service, char *proto)
{
struct servent *ent;
#ifdef ENABLE_STATIC
ent = fallback_service(service, proto);
#else
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
ent = fallback_proto(proto);
#else
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)
{
if (!fexist("/etc/services") || !fexist("/etc/protocols")) {
_w("Cannot register inetd %s/%s, system missing /etc/services or /etc/protocols", service, proto);
return errno = ECANCELED;
}
*sv = getent_service(service, proto);
if (!*sv) {
const char *errstr;
static struct servent s;
s.s_name = service;
s.s_port = strtonum(service, 1, UINT16_MAX, &errstr);
s.s_proto = NULL;
if (!strcmp("tcp", proto) || !strcmp("udp", proto))
s.s_proto = proto;
if (errstr || !s.s_proto) {
_e("Invalid/unknown inetd service, cannot create custom entry");
return errno = EINVAL;
}
_d("Creating cutom inetd service %s/%s", service, proto);
s.s_port = htons(s.s_port);
*sv = &s;
}
if (pv && (*sv)->s_proto) {
*pv = getent_proto((*sv)->s_proto);
if (!*pv) {
_e("Cannot find proto %s, skipping ...", (*sv)->s_proto);
return errno = EINVAL;
}
}
return 0;
}
/*
* Find exact match.
*/
static inetd_filter_t *find_filter(inetd_t *inetd, char *ifname)
{
inetd_filter_t *filter;
if (!ifname)
ifname = "*";
TAILQ_FOREACH(filter, &inetd->filters, link) {
_d("Checking filters for %s: '%s' vs '%s' (exact match) ...",
inetd->name, filter->ifname, ifname);
if (!strcmp(filter->ifname, ifname))
return filter;
}
return NULL;
}
/*
* First try exact match, then fall back to any match.
*/
inetd_filter_t *inetd_filter_match(inetd_t *inetd, char *ifname)
{
inetd_filter_t *filter = find_filter(inetd, ifname);
if (filter)
return filter;
TAILQ_FOREACH(filter, &inetd->filters, link) {
_d("Checking filters for %s: '%s' vs '%s' (any match) ...",
inetd->name, filter->ifname, ifname);
if (!strcmp(filter->ifname, "*"))
return filter;
}
return NULL;
}
int inetd_flush(inetd_t *inetd)
{
inetd_filter_t *filter, *next;
TAILQ_FOREACH_SAFE(filter, &inetd->filters, link, next) {
TAILQ_REMOVE(&inetd->filters, filter, link);
free(filter);
}
return 0;
}
/* Poor man's tcpwrappers filtering */
int inetd_allow(inetd_t *inetd, char *ifname)
{
inetd_filter_t *filter;
if (!inetd)
return errno = EINVAL;
if (!ifname)
ifname = "*";
filter = inetd_filter_match(inetd, ifname);
if (filter) {
_d("Filter %s for inetd %s already exists, skipping ...", ifname, inetd->name);
return 0;
}
_d("Allow iface %s for service %s (port %d)", ifname, inetd->name, inetd->port);
filter = calloc(1, sizeof(*filter));
if (!filter) {
_e("Out of memory, cannot add filter to service %s", inetd->name);
return errno = ENOMEM;
}
filter->deny = 0;
strlcpy(filter->ifname, ifname, sizeof(filter->ifname));
TAILQ_INSERT_TAIL(&inetd->filters, filter, link);
return 0;
}
int inetd_deny(inetd_t *inetd, char *ifname)
{
inetd_filter_t *filter;
if (!inetd)
return errno = EINVAL;
if (!ifname)
ifname = "*";
filter = find_filter(inetd, ifname);
if (filter) {
_d("%s filter %s for inetd %s already exists, cannot set deny filter for same, skipping ...",
filter->deny ? "Deny" : "Allow", ifname, inetd->name);
return 1;
}
_d("Deny iface %s for service %s (port %d)", ifname, inetd->name, inetd->port);
filter = calloc(1, sizeof(*filter));
if (!filter) {
_e("Out of memory, cannot add filter to service %s", inetd->name);
return errno = ENOMEM;
}
filter->deny = 1;
strlcpy(filter->ifname, ifname, sizeof(filter->ifname));
TAILQ_INSERT_TAIL(&inetd->filters, filter, link);
return 0;
}
int inetd_is_allowed(inetd_t *inetd, char *ifname)
{
inetd_filter_t *filter;
if (!inetd) {
errno = EINVAL;
return 0;
}
filter = inetd_filter_match(inetd, ifname);
if (filter) {
_d("Found matching filter for %s, deny: %d ... ", inetd->name, filter->deny);
return !filter->deny;
}
_d("No matching filter for %s ... ", inetd->name);
return 0;
}
int inetd_match(inetd_t *inetd, char *service, char *proto)
{
struct servent *sv = NULL;
struct protoent *pv = NULL;
if (!inetd || !service || !proto)
return errno = EINVAL;
if (strncmp(inetd->name, service, sizeof(inetd->name)))
return 0;
if (getent(service, proto, &sv, &pv))
return 0;
if (inetd->proto == ntohs(pv->p_proto) &&
inetd->port == ntohs(sv->s_port))
return 1;
return 0;
}
/* Compose presentable string of inetd filters: !eth0,eth1,eth2,!eth3 */
int inetd_filter_str(inetd_t *inetd, char *str, size_t len)
{
int prev = 0;
char buf[42];
inetd_filter_t *filter;
if (!inetd || !str || len <= 0) {
_e("Dafuq?");
return 1;
}
snprintf(str, len, "%s allow %s ", inetd->name,
inetd->type == SOCK_DGRAM ? "UDP" : "TCP");
TAILQ_FOREACH(filter, &inetd->filters, link) {
char ifname[IFNAMSIZ];
if (filter->deny)
continue;
if (!strlen(filter->ifname))
snprintf(ifname, sizeof(ifname), "*");
else
strlcpy(ifname, filter->ifname, sizeof(ifname));
snprintf(buf, sizeof(buf), "%s%s:%d", prev ? "," : "",
ifname, inetd->port);
prev = 1;
strlcat(str, buf, len);
}
prev = 0;
TAILQ_FOREACH(filter, &inetd->filters, link) {
char ifname[IFNAMSIZ];
if (!filter->deny)
continue;
if (!prev) {
snprintf(buf, sizeof(buf), " deny ");
strlcat(str, buf, len);
}
if (!strlen(filter->ifname))
snprintf(ifname, sizeof(ifname), "*");
else
strlcpy(ifname, filter->ifname, sizeof(ifname));
snprintf(buf, sizeof(buf), "%s%s", prev ? "," : "", ifname);
prev = 1;
strlcat(str, buf, 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
* interface. If a similar service runs on another port, this function
* must add this ifname as "deny" to that other service.
*
* Example:
* inetd ssh@eth0:222/tcp nowait [2345] /usr/sbin/sshd -i
* inetd ssh/tcp nowait [2345] /usr/sbin/sshd -i
*
* In this example eth0:222 is very specific, so when ssh/tcp (default)
* is added we must find the previous 'ssh' service and add its eth0 as
* deny, so we don't accept port 22 session on eth0.
*
* In the reverse case, where the default (ssh/tcp) entry is listed
* before the specific (eth0:222), the new inetd service must find the
* (any!) previous rule and add its ifname to their deny list.
*
* If equivalent service exists already service_register() will instead call
* inetd_allow().
*/
int inetd_new(inetd_t *inetd, char *name, char *service, char *proto, int forking, svc_t *svc)
{
int result;
struct servent *sv = NULL;
struct protoent *pv = NULL;
if (!inetd || !service || !proto)
return errno = EINVAL;
result = getent(service, proto, &sv, &pv);
if (result)
return result;
/* Setup defaults */
inetd->std = 1;
inetd->port = ntohs(sv->s_port);
inetd->proto = pv->p_proto;
inetd->forking = !!forking;
inetd->next_id = 2;
if (!name)
name = service;
strlcpy(inetd->name, name, sizeof(inetd->name));
TAILQ_INIT(&inetd->filters);
/* Naïve mapping tcp->stream, udp->dgram, other->dgram */
if (!strcasecmp(sv->s_proto, "tcp"))
inetd->type = SOCK_STREAM;
else
inetd->type = SOCK_DGRAM;
if (inetd->type == SOCK_DGRAM && inetd->forking) {
logit(LOG_WARNING, "%s: 'nowait' is not applicable on UDP services, ignoring", svc->cmd);
inetd->forking = 0;
}
/* Reset descriptor, used internally */
inetd->watcher.fd = -1;
/* Setup socket callback argument */
inetd->svc = svc;
_d("New service %s (default port %d proto %s:%d)", name, inetd->port, sv->s_proto, pv->p_proto);
return 0;
}
int inetd_del(inetd_t *inetd)
{
svc_unblock(inetd->svc);
inetd_stop(inetd);
return inetd_flush(inetd);
}
/**
* Local Variables:
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/
+82
View File
@@ -0,0 +1,82 @@
/* Classic inetd services launcher for Finit
*
* Copyright (c) 2015 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_INETD_H_
#define FINIT_INETD_H_
#include <netdb.h>
#include <net/if.h>
#include <uev/uev.h>
#include <lite/queue.h> /* BSD sys/queue.h API */
typedef struct svc svc_t;
typedef struct inetd_filter {
TAILQ_ENTRY(inetd_filter) link;
int deny; /* 0:allow, 1:deny */
char ifname[IFNAMSIZ]; /* E.g., eth0 */
} inetd_filter_t;
typedef struct {
uev_t watcher;
svc_t *svc; /* svc_t pointer for the socket callback */
int type; /* Socket type: SOCK_STREAM/SOCK_DGRAM */
int std; /* Standard proto/port from /etc/services */
int proto;
int port;
int forking;
int builtin; /* Set by built-in inetd services only */
int next_id; /* Next child job's id */
char name[10];
int (*cmd)(int type); /* internal inetd service, like 'time' */
TAILQ_HEAD(, inetd_filter) filters;
} inetd_t;
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_new (inetd_t *inetd, char *name, char *service, char *proto, int forking, svc_t *svc);
int inetd_del (inetd_t *inetd);
svc_t *inetd_find_svc (char *path, char *service, char *proto);
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_ */
/**
* Local Variables:
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/
+516
View File
@@ -0,0 +1,516 @@
/* New client tool, complements old /dev/initctl API and telinit tool
*
* Copyright (c) 2015-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 <err.h>
#include <ctype.h>
#include <getopt.h>
#include <glob.h>
#include <paths.h>
#include <signal.h>
#include <stdio.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <lite/lite.h>
#include "config.h"
#include "finit.h"
#include "cond.h"
#include "helpers.h"
#include "service.h"
#include "util.h"
#include "utmp-api.h"
#define _PATH_COND _PATH_VARRUN "finit/cond/"
typedef struct {
char *cmd;
int (*cb)(char *arg);
} command_t;
int debug = 0;
int verbose = 0;
int silent = 1; /* For helpers.c */
int runlevel = 0;
static int do_send(struct init_request *rq, ssize_t len)
{
int sd, result = 255;
struct sockaddr_un sun = {
.sun_family = AF_UNIX,
.sun_path = INIT_SOCKET,
};
sd = socket(AF_UNIX, SOCK_STREAM, 0);
if (-1 == sd)
return -1;
if (connect(sd, (struct sockaddr*)&sun, sizeof(sun)) == -1)
goto error;
if (write(sd, rq, len) != len)
goto error;
if (read(sd, rq, len) != len)
goto error;
result = 0;
goto exit;
error:
perror("Failed communicating with finit");
exit:
close(sd);
return result;
}
static int runlevel_get(void)
{
int sd, result = 255;
struct init_request rq;
struct sockaddr_un sun = {
.sun_family = AF_UNIX,
.sun_path = INIT_SOCKET,
};
memset(&rq, 0, sizeof(rq));
rq.cmd = INIT_CMD_GET_RUNLEVEL;
rq.magic = INIT_MAGIC;
sd = socket(AF_UNIX, SOCK_STREAM, 0);
if (-1 == sd)
return -1;
if (connect(sd, (struct sockaddr*)&sun, sizeof(sun)) == -1)
goto error;
if (write(sd, &rq, sizeof(rq)) != sizeof(rq))
goto error;
if (read(sd, &rq, sizeof(rq)) != sizeof(rq))
goto error;
result = rq.runlevel;
goto exit;
error:
perror("Failed communicating with finit");
result = -1;
exit:
close(sd);
return result;
}
static int toggle_debug(char *UNUSED(arg))
{
struct init_request rq = {
.magic = INIT_MAGIC,
.cmd = INIT_CMD_DEBUG,
};
return do_send(&rq, sizeof(rq));
}
static int do_runlevel(char *arg)
{
struct init_request rq = {
.magic = INIT_MAGIC,
.cmd = INIT_CMD_RUNLVL,
.runlevel = (int)arg[0],
};
/* Not compatible with the SysV runlevel(8) command, it prints
* "PREVLEVEL RUNLEVEL", we just print the current runlevel. */
if (!rq.runlevel) {
printf("%d\n", runlevel_get());
return 0;
}
return do_send(&rq, sizeof(rq));
}
static int do_svc(int cmd, char *arg)
{
struct init_request rq = {
.magic = INIT_MAGIC,
.cmd = cmd,
};
strlcpy(rq.data, arg, sizeof(rq.data));
return do_send(&rq, sizeof(rq));
}
static int do_emit (char *arg) { return do_svc(INIT_CMD_EMIT, arg); }
static int do_reload (char *arg) { return do_svc(INIT_CMD_RELOAD, arg); }
static int do_start (char *arg) { return do_svc(INIT_CMD_START_SVC, arg); }
static int do_stop (char *arg) { return do_svc(INIT_CMD_STOP_SVC, arg); }
static int do_restart(char *arg) { return do_svc(INIT_CMD_RESTART_SVC, arg); }
static void show_cond_one(const char *_conds)
{
static char conds[MAX_ARG_LEN];
char *cond;
strlcpy(conds, _conds, sizeof(conds));
putchar('<');
for (cond = strtok(conds, ","); cond; cond = strtok(NULL, ",")) {
if (cond != conds)
putchar(',');
switch (cond_get(cond)) {
case COND_ON:
printf("+%s", cond);
break;
case COND_FLUX:
printf("\e[1m~%s\e[0m", cond);
break;
case COND_OFF:
printf("\e[1m-%s\e[0m", cond);
break;
}
}
putchar('>');
}
static int do_cond_magic(char op, char *cond)
{
cond[0] = op;
return do_emit(cond);
}
static int do_cond_set (char *cond) { return do_cond_magic('+', cond); }
static int do_cond_clear(char *cond) { return do_cond_magic('-', cond); }
static int do_cond_show(char *UNUSED(arg))
{
svc_t *svc;
enum cond_state cond;
if (verbose) {
glob_t gl;
printf("Asserted conditions (taken from %s)\n", _PATH_COND);
printf("===============================================================================\n");
if (!glob(_PATH_COND "*/*/*", 0, NULL, &gl)) {
size_t i;
for (i = 0; i < gl.gl_pathc; i++) {
char *cond, *name = gl.gl_pathv[i];
struct stat st;
if (stat(name, &st) || S_ISDIR(st.st_mode))
continue;
cond = name + strlen(_PATH_COND);
printf("\t%s\n", cond);
}
globfree(&gl);
}
puts("");
}
printf("PID Service Status Condition (+ on, ~ flux, - off)\n");
printf("===============================================================================\n");
for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) {
if (!svc->cond[0])
continue;
cond = cond_get_agg(svc->cond);
printf("%-6d %-20.20s ", svc->pid, svc->cmd);
if (cond == COND_ON)
printf("%-6.6s ", condstr(cond));
else
printf("\e[1m%-6.6s\e[0m ", condstr(cond));
show_cond_one(svc->cond);
puts("");
}
return 0;
}
static int do_cond(char *cmd)
{
int c;
char *arg;
command_t command[] = {
{ "set", do_cond_set },
{ "clear", do_cond_clear },
{ "show", do_cond_show },
{ NULL, NULL }
};
arg = strpbrk(cmd, " ");
if (arg) {
*arg = 0;
for (c = 0; command[c].cmd; c++) {
if (!strcmp(command[c].cmd, cmd))
return command[c].cb(arg);
}
}
return do_cond_show(NULL);
}
static int do_signal(int signo, const char *msg)
{
if (kill(1, signo))
err(1, "Failed signalling init to %s", msg);
return 0;
}
static int do_halt (char *UNUSED(arg)) { return do_signal(SIGUSR1, "halt"); }
static int do_poweroff(char *UNUSED(arg)) { return do_signal(SIGUSR2, "power off"); }
static int do_reboot (char *UNUSED(arg)) { return do_signal(SIGTERM, "reboot"); }
static int do_utmp(char *UNUSED(cmd))
{
return utmp_show(_PATH_WTMP) ||
utmp_show(_PATH_UTMP);
}
static int show_version(char *UNUSED(arg))
{
puts("v" PACKAGE_VERSION);
return 0;
}
/* In verbose mode we skip the header and each service description.
* This in favor of having all info on one line so a machine can more
* easily parse it. */
static int show_status(char *arg)
{
svc_t *svc;
/* Fetch UTMP runlevel, needed for svc_status() call below */
runlevel = runlevel_get();
if (arg && arg[0]) {
int id = 1;
char *ptr, *next;
ptr = strchr(arg, ':');
if (ptr) {
*ptr++ = 0;
next = strchr(ptr, ' ');
if (next)
*next = 0;
id = atonum(ptr);
}
if (isdigit(arg[0]))
svc = svc_find_by_jobid(atonum(arg), id);
else
svc = svc_find_by_nameid(arg, id);
if (!svc)
return 1;
printf("%s\n", svc_status(svc));
return 0;
}
if (!verbose) {
printf("# Status PID Runlevels Service Description\n");
printf("===============================================================================\n");
}
for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) {
char jobid[10], args[512] = "", *lvls;
if (svc_is_unique(svc))
snprintf(jobid, sizeof(jobid), "%d", svc->job);
else
snprintf(jobid, sizeof(jobid), "%d:%d", svc->job, svc->id);
printf("%-5s %7s ", jobid, svc_status(svc));
if (svc_is_inetd(svc))
printf("inetd ");
else
printf("%-6d ", svc->pid);
lvls = runlevel_string(svc->runlevels);
if (strchr(lvls, '\e'))
printf("%-18.18s ", lvls);
else
printf("%-10.10s ", lvls);
if (!verbose) {
char *name = strrchr(svc->cmd, '/');
if (!name)
name = svc->cmd;
else
name++;
printf("%-20.20s %-21.21s\n", name, svc->desc);
continue;
}
#ifndef INETD_DISABLED
if (svc_is_inetd(svc)) {
char *info;
struct init_request rq = {
.magic = INIT_MAGIC,
.cmd = INIT_CMD_QUERY_INETD,
};
snprintf(rq.data, sizeof(rq.data), "%s", jobid);
if (do_send(&rq, sizeof(rq))) {
snprintf(args, sizeof(args), "Unknown inetd");
info = args;
} else {
info = rq.data;
if (strcmp("internal", svc->cmd)) {
char *ptr = strchr(info, ' ');
if (ptr)
info = ptr + 1;
}
}
printf("%s %s\n", svc->cmd, info);
}
else
#endif /* !INETD_DISABLED */
{
int i;
for (i = 1; i < MAX_NUM_SVC_ARGS; i++) {
strlcat(args, svc->args[i], sizeof(args));
strlcat(args, " ", sizeof(args));
}
printf("%s %s\n", svc->cmd, args);
}
}
return 0;
}
static int usage(int rc)
{
fprintf(stderr, "Usage: %s [OPTIONS] <COMMAND>\n\n"
"Options:\n"
" -d, --debug Debug initctl (client)\n"
" -v, --verbose Verbose output\n"
" -h, --help This help text\n\n"
"Commands:\n"
" debug Toggle Finit (daemon) debug\n"
" help This help text\n"
" reload Reload *.conf in /etc/finit.d and activate changes\n"
" runlevel [0-9] Show or set runlevel: 0 halt, 6 reboot\n"
" status | show Show status of services\n"
" cond set <COND> Set (assert) condition => +COND\n"
" cond clear <COND> Clear (deassert) condition => -COND\n"
" cond show Show condition status\n"
" start <JOB|NAME>[:ID] Start service by job# or name, with optional ID\n"
" stop <JOB|NAME>[:ID] Stop/Pause a running service by job# or name\n"
" restart <JOB|NAME>[:ID] Restart (stop/start) service by job# or name\n"
" reboot Reboot system\n"
" 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", prognm);
return rc;
}
int main(int argc, char *argv[])
{
int c;
command_t command[] = {
{ "debug", toggle_debug },
{ "reload", do_reload },
{ "runlevel", do_runlevel },
{ "status", show_status },
{ "show", show_status }, /* Convenience alias */
{ "cond", do_cond },
{ "start", do_start },
{ "stop", do_stop },
{ "restart", do_restart },
{ "reboot", do_reboot },
{ "halt", do_halt },
{ "poweroff", do_poweroff },
{ "utmp", do_utmp },
{ "version", show_version },
{ NULL, NULL }
};
struct option long_options[] = {
{"help", 0, NULL, 'h'},
{"debug", 0, NULL, 'd'},
{"verbose", 0, NULL, 'v'},
{NULL, 0, NULL, 0}
};
progname(argv[0]);
while ((c = getopt_long(argc, argv, "dh?v", long_options, NULL)) != EOF) {
switch(c) {
case 'h':
case '?':
return usage(0);
case 'd':
debug = 1;
break;
case 'v':
verbose = 1;
break;
}
}
silent = !verbose;
if (optind < argc) {
char *cmd = argv[optind++];
char arg[120] = "";
while (optind < argc) {
strlcat(arg, argv[optind++], sizeof(arg));
strlcat(arg, " ", sizeof(arg));
}
for (c = 0; command[c].cmd; c++) {
if (!strcmp(command[c].cmd, cmd))
return command[c].cb(arg);
}
}
return usage(1);
}
/**
* Local Variables:
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/
+2
View File
@@ -0,0 +1,2 @@
*.m4
!plugin.m4
+17
View File
@@ -0,0 +1,17 @@
# From https://github.com/kakaroto/e17/blob/master/BINDINGS/javascript/elixir/m4/ac_expand_dir.m4
# By Alexandre Oliva <oliva@dcc.unicamp.br>
# AC_EXPAND_DIR(VARNAME, DIR)
# ------------------------------------------------------------
# Expands occurrences of ${prefix} and ${exec_prefix} in the
# given DIR, and assigns the resulting string to VARNAME
#
# Example: AC_DEFINE_DIR(DATADIR, "$datadir")
AC_DEFUN([AC_EXPAND_DIR], [
$1=$2
$1=`(
test "x$prefix" = xNONE && prefix="$ac_default_prefix"
test "x$exec_prefix" = xNONE && exec_prefix="${prefix}"
eval echo \""[$]$1"\"
)`
])
+35
View File
@@ -0,0 +1,35 @@
# From https://github.com/collectd/collectd/blob/master/configure.ac
# Dependency handling currently unused
define([toupper], [translit([$1], [a-z], [A-Z])])
define([sanitize], [translit([$1], [-], [_])])
define([enadis], [ifelse([$1], [yes], [disable], [enable])])
# AC_PLUGIN(name, default, info)
# ------------------------------------------------------------
AC_DEFUN([AC_PLUGIN],[
m4_divert_once([HELP_ENABLE], [
Optional Plugins:])
enable_plugin="no"
define(pluggy, sanitize($1))
define(PLUGGY, toupper(pluggy))
AC_ARG_ENABLE([$1-plugin], AS_HELP_STRING([--enadis($2)-$1-plugin], [$3]), [
if test "x$enableval" = "xyes"; then
enable_plugin="yes"
else
enable_plugin="no"
fi], [
if test "x$enable_all_plugins" = "xauto"; then
if test "x$2" = "xyes"; then
enable_plugin="yes"
else
enable_plugin="no"
fi
else
enable_plugin="$enable_all_plugins"
fi])
if test "x$enable_plugin" = "xyes"; then
AC_DEFINE([HAVE_]PLUGGY[_PLUGIN], 1, [Define to 1 if the $1 plugin is enabled.])
fi
AM_CONDITIONAL([BUILD_]PLUGGY[_PLUGIN], test "x$enable_plugin" = "xyes")
enable_pluggy="$enable_plugin"])
+72
View File
@@ -0,0 +1,72 @@
/* Handle MD arrays
*
* 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 <stdio.h>
#include <string.h>
#include "helpers.h"
static glob_t *get_arrays(void)
{
static glob_t arrays;
glob("/sys/block/md*", 0, NULL, &arrays);
if (arrays.gl_pathc > 0)
return &arrays;
return NULL;
}
/*
* If system has an MD raid, we must tell it to stop before continuing
* with the shutdown. Some controller cards, in particular the Intel(R)
* Matrix Storage Manager, must be properly notified.
*/
void mdadm_wait(void)
{
size_t i;
glob_t *gl;
char cmd[160];
/* Setup kernel specific settings, e.g. allow broadcast ping, etc. */
gl = get_arrays();
if (gl) {
for (i = 0; i < gl->gl_pathc; i++) {
char *array;
array = basename(gl->gl_pathv[i]);
snprintf(cmd, sizeof(cmd), "mdadm --wait-clean /dev/%s >/dev/null", array);
run_interactive(cmd, "Marking MD array %s as clean", array);
}
globfree(gl);
}
}
/**
* Local Variables:
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/
+110
View File
@@ -0,0 +1,110 @@
/* Mount and unmount helpers
*
* 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>
#include <mntent.h>
#include <sys/mount.h>
/*
* SysV init on Debian/Ubuntu skips these protected mount points
*
* It also skips anything below /proc, /sys and /run for good meausre so
* we do the same here. What we want is a list of non-protected tmpfs
* and regular filesystems that can be safely unmounted before we do
* swapoff, and remount / as read-only, respectively.
*/
static int is_protected(char *dir)
{
size_t i;
char *protected[] = {
"/sys", "/proc",
"/.dev", "/dev", "/dev/pts", "/dev/shm", "dev/.static/dev", "/dev/vcs",
"/run", "/var/run",
"/", NULL
};
char *any[] = {
"/proc/", "/sys/", "/run/", NULL
};
for (i = 0; protected[i]; i++) {
if (!strcmp(dir, protected[i]))
return 1;
}
for (i = 0; any[i]; i++) {
if (!strncmp(dir, any[i], strlen(any[i])))
return 1;
}
return 0;
}
static struct mntent *iterator(char *fstab)
{
static FILE *fp = NULL;
static struct mntent *mnt;
if (!fp && fstab) {
fp = setmntent(fstab, "r");
if (!fp)
return NULL;
}
while ((mnt = getmntent(fp))) {
if (is_protected(mnt->mnt_dir))
continue;
return mnt;
}
endmntent(fp);
fp = NULL;
return NULL;
}
void unmount_tmpfs(void)
{
struct mntent *mnt;
while ((mnt = iterator("/proc/mounts"))) {
if (!strcmp("tmpfs", mnt->mnt_fsname))
umount(mnt->mnt_dir);
}
}
void unmount_regular(void)
{
struct mntent *mnt;
while ((mnt = iterator("/proc/mounts"))) {
umount(mnt->mnt_dir);
}
}
/**
* Local Variables:
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/
+98
View File
@@ -0,0 +1,98 @@
/* Misc. utility functions and C-library extensions for finit and its plugins
*
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
* Copyright (c) 2008-2015 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 <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <lite/lite.h>
#include "helpers.h"
/**
* pid_alive - Check if a given process ID is running
* @pid: Process ID to check for.
*
* Returns:
* %TRUE(1) if pid is alive (/proc/pid exists), otherwise %FALSE(0)
*/
int pid_alive(pid_t pid)
{
char name[24]; /* Enough for max pid_t */
snprintf(name, sizeof(name), "/proc/%d", pid);
return fexist(name);
}
/**
* pid_get_name - Find name of a process
* @pid: PID of process to find.
* @name: Pointer to buffer where to return process name, may be %NULL
* @len: Length in bytes of @name buffer.
*
* If @name is %NULL, or @len is zero the function will return
* a static string. This may be useful to one-off calls.
*
* Returns:
* %NULL on error, otherwise a va
*/
char *pid_get_name(pid_t pid, char *name, size_t len)
{
int ret = 1;
FILE *fp;
char *pname, path[32];
static char line[64];
snprintf(path, sizeof(path), "/proc/%d/status", pid);
fp = fopen(path, "r");
if (fp) {
if (fgets(line, sizeof (line), fp)) {
pname = line + 6; /* Skip first part of line --> "Name:\t" */
chomp(pname);
if (name)
strlcpy(name, pname, len);
ret = 0; /* Found it! */
}
fclose(fp);
}
if (ret)
return NULL;
if (name)
return name;
return pname;
}
/**
* Local Variables:
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/
+309 -155
View File
@@ -26,196 +26,350 @@
#include <dirent.h> /* readdir() et al */ #include <dirent.h> /* readdir() et al */
#include <poll.h> #include <poll.h>
#include <string.h> #include <string.h>
#include <sys/queue.h> /* BSD sys/queue.h API */ #include <lite/lite.h>
#include <lite/queue.h> /* BSD sys/queue.h API */
#include "config.h"
#include "finit.h" #include "finit.h"
#include "private.h" #include "private.h"
#include "helpers.h" #include "helpers.h"
#include "plugin.h" #include "plugin.h"
#include "svc.h"
#define is_io_plugin(p) ((p)->io.cb && (p)->io.fd >= 0) #define is_io_plugin(p) ((p)->io.cb && (p)->io.fd > 0)
#define SEARCH_PLUGIN(str) \
PLUGIN_ITERATOR(p, tmp) { \
if (!strcmp(p->name, str)) \
return p; \
}
static size_t num_fds = 0; static char *plugpath = NULL; /* Set by first load. */
static struct pollfd fds[MAX_NUM_FDS]; static TAILQ_HEAD(plugin_head, plugin) plugins = TAILQ_HEAD_INITIALIZER(plugins);
static LIST_HEAD(, plugin) plugins = LIST_HEAD_INITIALIZER();
#ifndef ENABLE_STATIC
static void check_plugin_depends(plugin_t *plugin);
#endif
static char *trim_ext(char *name)
{
char *ptr;
if (name) {
ptr = strstr(name, ".so");
if (!ptr)
ptr = strstr(name, ".c");
if (ptr)
*ptr = 0;
}
return name;
}
int plugin_register(plugin_t *plugin) int plugin_register(plugin_t *plugin)
{ {
int inuse = 0;
if (!plugin) { if (!plugin) {
errno = EINVAL; errno = EINVAL;
return 1; return 1;
} }
/* Setup default name if none is provided */
if (!plugin->name) { if (!plugin->name) {
#ifndef ENABLE_STATIC
Dl_info info; Dl_info info;
if (!dladdr(plugin, &info) || !info.dli_fname) if (dladdr(plugin, &info) && info.dli_fname)
plugin->name = basename(info.dli_fname);
#endif
if (!plugin->name)
plugin->name = "unknown"; plugin->name = "unknown";
else }
plugin->name = (char *)info.dli_fname; plugin->name = trim_ext(strdup(plugin->name));
/* Already registered? */
if (plugin_find(plugin->name)) {
_d("... %s already loaded", plugin->name);
free(plugin->name);
return 0;
} }
if (is_io_plugin(plugin)) { #ifndef ENABLE_STATIC
if (num_fds + 1 >= MAX_NUM_FDS) { /* Resolve plugin dependencies */
num_fds = MAX_NUM_SVC; check_plugin_depends(plugin);
errno = ENOMEM; #endif
return 1;
}
num_fds++;
inuse++;
}
if (plugin->svc.cb) { TAILQ_INSERT_TAIL(&plugins, plugin, link);
svc_t *svc = svc_find_by_name(plugin->name);
if (svc) {
plugin->svc.id = svc_id(svc);
svc->plugin = &plugin->svc;
inuse++;
}
}
if (!inuse) {
_e("No service \"%s\" loaded, skipping plugin.", basename(plugin->name));
return 1;
}
LIST_INSERT_HEAD(&plugins, plugin, link);
return 0; return 0;
} }
/* Not called, at the moment plugins cannot be unloaded. */
int plugin_unregister(plugin_t *plugin) int plugin_unregister(plugin_t *plugin)
{ {
LIST_REMOVE(plugin, link); #ifndef ENABLE_STATIC
TAILQ_REMOVE(&plugins, plugin, link);
/* XXX: Unfinished, add cleanup code here! */ _d("%s exiting ...", plugin->name);
free(plugin->name);
return 0; #else
} _d("Finit built statically, cannot unload %s ...", plugin->name);
#endif
/* Private daemon API *******************************************************/
void run_hooks(hook_point_t no)
{
plugin_t *p;
PLUGIN_ITERATOR(p) {
if (p->hook[no].cb) {
_d("Calling %s hook n:o %d from runloop...", basename(p->name), no);
p->hook[no].cb(p->hook[no].arg);
}
}
}
void run_services(void)
{
plugin_t *p;
PLUGIN_ITERATOR(p) {
if (p->svc.cb) {
_d("Calling svc %s from runloop...", basename(p->name));
p->svc.cb(p->svc.arg, 0);
}
}
}
/* Generic libev I/O callback, looks up correct plugin and calls its callback */
static void generic_io_cb(int fd, int events)
{
plugin_t *p;
/* Find matching plugin, pick first matching fd */
PLUGIN_ITERATOR(p) {
if (is_io_plugin(p) && p->io.fd == fd) {
_d("Calling I/O %s from runloop...", basename(p->name));
p->io.cb(p->io.arg, fd, events);
break;
}
}
}
void io_monitor(void)
{
int ret;
size_t i;
while ((ret = poll(fds, num_fds, 500))) {
if (-1 == ret) {
if (EINTR == errno)
continue;
_e("Failed polling I/O plugin descriptors, error %d: %s",
errno, strerror(errno));
break;
}
/* Traverse all I/O fds and run callbacks */
for (i = 0; i < num_fds; i++) {
if (fds[i].revents)
generic_io_cb(fds[i].fd, fds[i].revents);
}
break;
}
}
/* Setup any I/O callbacks for plugins that use them */
static void init_plugins(void)
{
int i = 0;
plugin_t *p;
PLUGIN_ITERATOR(p) {
if (is_io_plugin(p)) {
_d("Initializing plugin %s for I/O", basename(p->name));
fds[i].revents = 0;
fds[i].events = p->io.flags;
fds[num_fds++].fd = p->io.fd;
}
}
}
int load_plugins(char *path)
{
DIR *dp = opendir(path);
struct dirent *entry;
if (!dp) {
_e("Failed, cannot open plugin directory %s: %s", path, strerror(errno));
return 1;
}
while ((entry = readdir(dp))) {
char *ext = entry->d_name + strlen(entry->d_name) - 3;
if (!strcmp(ext, ".so")) {
void *handle;
char filename[1024];
snprintf(filename, sizeof(filename), "%s/%s", path, entry->d_name);
print_descr(" Loading plugin ", basename(filename));
handle = dlopen(filename, RTLD_LAZY);
if (!handle) {
_d("Failed loading plugin %s: %s", filename, dlerror());
print_result(1);
return 1;
}
print_result(0);
}
}
closedir(dp);
init_plugins();
return 0; return 0;
} }
/**
* plugin_find - Find a plugin by name
* @name: With or without path, or .so extension
*
* This function uses an opporunistic search for a suitable plugin and
* returns the first match. Albeit with at least some measure of
* heuristics.
*
* First it checks for an exact match. If no match is found and @name
* starts with a slash the search ends. Otherwise a new search with the
* plugin path prepended to @name is made. Also, if @name does not end
* with .so it too is added to @name before searching.
*
* Returns:
* On success the pointer to the matching &plugin_t is returned,
* otherwise %NULL is returned.
*/
plugin_t *plugin_find(char *name)
{
plugin_t *p, *tmp;
if (!name) {
errno = EINVAL;
return NULL;
}
SEARCH_PLUGIN(name);
if (plugpath && name[0] != '/') {
int noext;
char path[CMD_SIZE];
noext = strcmp(name + strlen(name) - 3, ".so");
snprintf(path, sizeof(path), "%s%s%s%s", plugpath,
fisslashdir(plugpath) ? "" : "/",
name, noext ? ".so" : "");
SEARCH_PLUGIN(path);
}
errno = ENOENT;
return NULL;
}
/* Private daemon API *******************************************************/
/* Some hooks are called with a fixed argument, like HOOK_SVC_LOST */
void plugin_run_hook(hook_point_t no, void *arg)
{
plugin_t *p, *tmp;
PLUGIN_ITERATOR(p, tmp) {
if (p->hook[no].cb) {
_d("Calling %s hook n:o %d (arg: %p) ...", basename(p->name), no, arg);
p->hook[no].cb(arg ? arg : p->hook[no].arg);
}
}
}
/* Regular hooks are called with the registered plugin's argument */
void plugin_run_hooks(hook_point_t no)
{
plugin_run_hook(no, NULL);
}
/* Generic libev I/O callback, looks up correct plugin and calls its callback */
static void generic_io_cb(uev_t *w, void *arg, int events)
{
plugin_t *p = (plugin_t *)arg;
if (is_io_plugin(p) && p->io.fd == w->fd) {
/* Stop watcher, callback may close descriptor on us ... */
uev_io_stop(w);
_d("Calling I/O %s from runloop...", basename(p->name));
p->io.cb(p->io.arg, w->fd, events);
/* Update fd, may be changed by plugin callback, e.g., if FIFO */
uev_io_set(w, p->io.fd, p->io.flags);
}
}
int plugin_io_init(plugin_t *p)
{
if (!is_io_plugin(p))
return 0;
_d("Initializing plugin %s for I/O", basename(p->name));
if (uev_io_init(ctx, &p->watcher, generic_io_cb, p, p->io.fd, p->io.flags)) {
_e("Failed setting up I/O plugin %s", basename(p->name));
return 1;
}
return 0;
}
/* Setup any I/O callbacks for plugins that use them */
static int init_plugins(uev_ctx_t *UNUSED(ctx))
{
int fail = 0;
plugin_t *p, *tmp;
PLUGIN_ITERATOR(p, tmp) {
if (plugin_io_init(p))
fail++;
}
return fail;
}
#ifndef ENABLE_STATIC
/**
* load_one - Load one plugin
* @path: Path to finit plugins, usually %PLUGIN_PATH
* @name: Name of plugin, optionally ending in ".so"
*
* Loads a plugin from @path/@name[.so]. Note, if ".so" is missing from
* the plugin @name it is added before attempting to load.
*
* It is up to the plugin itself ot register itself as a "ctor" with the
* %PLUGIN_INIT macro so that plugin_register() is called automatically.
*
* Returns:
* POSIX OK(0) on success, non-zero otherwise.
*/
static int load_one(char *path, char *name)
{
int noext;
char sofile[CMD_SIZE];
void *handle;
plugin_t *plugin;
if (!path || !fisdir(path) || !name) {
errno = EINVAL;
return 1;
}
/* Compose full path, with optional .so extension, to plugin */
noext = strcmp(name + strlen(name) - 3, ".so");
snprintf(sofile, sizeof(sofile), "%s/%s%s", path, name, noext ? ".so" : "");
_d("Loading plugin %s ...", basename(sofile));
handle = dlopen(sofile, RTLD_LAZY | RTLD_LOCAL);
if (!handle) {
_e("Failed loading plugin %s: %s", sofile, dlerror());
return 1;
}
plugin = TAILQ_LAST(&plugins, plugin_head);
if (!plugin) {
_e("Plugin %s failed to register, unloading from memory", sofile);
dlclose(handle);
return 1;
}
/* Remember handle from dlopen() for plugin_unregister() */
plugin->handle = handle;
return 0;
}
/**
* check_plugin_depends - Check and load any plugins this one depends on.
* @plugin: Plugin with possible depends to check
*
* Very simple dependency resolver, should actually load the plugin of
* the correct .name, but currently loads a matching filename.
*
* Works, but only for now. A better way might be to have a try_load()
* that actually loads all plugins and checks their &plugin_t for the
* correct .name.
*/
static void check_plugin_depends(plugin_t *plugin)
{
int i;
for (i = 0; i < PLUGIN_DEP_MAX && plugin->depends[i]; i++) {
// _d("Plugin %s depends on %s ...", plugin->name, plugin->depends[i]);
if (plugin_find(plugin->depends[i])) {
// _d("OK plugin %s was already loaded.", plugin->depends[i]);
continue;
}
load_one(plugpath, plugin->depends[i]);
}
}
static int load_plugins(char *path)
{
int fail = 0;
DIR *dp;
struct dirent *entry;
if (!silent)
print_desc("Loading plugins", NULL);
dp = opendir(path);
if (!dp) {
_e("Failed, cannot open plugin directory %s: %s", path, strerror(errno));
return 1;
}
plugpath = path;
while ((entry = readdir(dp))) {
if (entry->d_name[0] == '.')
continue; /* Skip . and .. directories */
if (load_one(path, entry->d_name))
fail++;
}
closedir(dp);
return fail;
}
#else
static int load_plugins(char *UNUSED(path))
{
if (!silent)
print_desc("Initializing plugins", NULL);
return 0;
}
#endif /* ENABLE_STATIC */
int plugin_init(uev_ctx_t *ctx, char *path)
{
int fail = 1;
if (!load_plugins(path))
fail = init_plugins(ctx);
if (!silent)
print_result(fail);
return fail;
}
void plugin_exit(void)
{
#ifndef ENABLE_STATIC
plugin_t *p, *tmp;
PLUGIN_ITERATOR(p, tmp) {
if (dlclose(p->handle))
_e("Failed: unloading plugin %s: %s", p->name, dlerror());
}
#endif
}
/** /**
* Local Variables: * Local Variables:
* version-control: t
* indent-tabs-mode: t * indent-tabs-mode: t
* c-file-style: "linux" * c-file-style: "linux"
* End: * End:
+49 -26
View File
@@ -24,25 +24,43 @@
#ifndef FINIT_PLUGIN_H_ #ifndef FINIT_PLUGIN_H_
#define FINIT_PLUGIN_H_ #define FINIT_PLUGIN_H_
#include <poll.h> #include <uev/uev.h>
#include <sys/queue.h> /* BSD sys/queue.h API */ #include <lite/queue.h> /* BSD sys/queue.h API */
#define PLUGIN_IO_READ POLLIN #include "svc.h"
#define PLUGIN_IO_WRITE POLLOUT
#ifndef PLUGIN_PATH /* Fallback for --enable-static builds */
#define PLUGIN_PATH "/dev/null"
#endif
#define PLUGIN_DEP_MAX 10
#define PLUGIN_IO_READ UEV_READ
#define PLUGIN_IO_WRITE UEV_WRITE
#define PLUGIN_INIT(x) static void __attribute__ ((constructor)) x(void) #define PLUGIN_INIT(x) static void __attribute__ ((constructor)) x(void)
#define PLUGIN_EXIT(x) static void __attribute__ ((destructor)) x(void) #define PLUGIN_EXIT(x) static void __attribute__ ((destructor)) x(void)
#define PLUGIN_ITERATOR(x) LIST_FOREACH(x, &plugins, link) #define PLUGIN_ITERATOR(x, tmp) TAILQ_FOREACH_SAFE(x, &plugins, link, tmp)
/* /*
* Predefined hook points for easier plugin debugging * Predefined hook points for easier plugin debugging
*/ */
typedef enum { typedef enum {
HOOK_BASEFS_UP = 0, /* Bootstrap hooks */
HOOK_ROOTFS_UP = 0,
HOOK_MOUNT_ERROR,
HOOK_BASEFS_UP,
HOOK_NETWORK_UP, HOOK_NETWORK_UP,
HOOK_SYSTEM_UP,
HOOK_SVC_UP, HOOK_SVC_UP,
HOOK_SYSTEM_UP,
/* Runtime hooks */
HOOK_SVC_RECONF,
HOOK_SVC_LOST,
HOOK_SVC_START,
HOOK_RUNLEVEL_CHANGE,
/* Shutdown hooks */
HOOK_SHUTDOWN, HOOK_SHUTDOWN,
HOOK_MAX_NUM HOOK_MAX_NUM
} hook_point_t; } hook_point_t;
@@ -65,7 +83,8 @@ typedef enum {
* The "dynamic events" discussed in the svc callback is for external * The "dynamic events" discussed in the svc callback is for external
* service plugins to implement. However, it can be anything that * service plugins to implement. However, it can be anything that
* can cause a service to need to SIGHUP at runtime. E.g., acquiring * can cause a service to need to SIGHUP at runtime. E.g., acquiring
* a DHCP lease, or an interface going UP/DOWN. * a DHCP lease, or an interface going UP/DOWN. The event itself can
* be passed as an integer @event and any optional argument @event_arg
* *
* It is up to the external service plugin to track these events and * It is up to the external service plugin to track these events and
* relay them to each @dynamic service plugins' callback. I.e., to * relay them to each @dynamic service plugins' callback. I.e., to
@@ -73,23 +92,18 @@ typedef enum {
*/ */
typedef struct plugin { typedef struct plugin {
/* BSD sys/queue.h linked list node. */ /* BSD sys/queue.h linked list node. */
LIST_ENTRY(plugin) link; TAILQ_ENTRY(plugin) link;
/* Plugin name, defaults to plugin path if unset. /* Handle to be sent to dlclose() when plugins is unloaded. */
* NOTE: Must be same as @cmd for service plugins! */ void *handle;
/* Event loop handler, used internally by Finit */
uev_t watcher;
/* Plugin name, defaults to basename of plugin path if unset.
* NOTE: Must match cmd for services or inetd plugins! */
char *name; char *name;
/* Service callback to be called once per lap of runloop. */
struct plugin_svc {
/* Private */
int id; /* Service ID# to match this service plugin against, set on installation. */
/* Public */
void *arg; /* Optional argument to callback func, set by plugin. */
int dynamic; /* Reload (SIGHUP) on dynamic event? Set by plugin. */
int private; /* For callbacks to use freely, possibly to store "states", set by plugin. */
int (*cb)(void *arg, int event);
} svc;
/* List of hook callbacks. */ /* List of hook callbacks. */
struct { struct {
void *arg; /* Optional argument to callback func. */ void *arg; /* Optional argument to callback func. */
@@ -102,20 +116,29 @@ typedef struct plugin {
void *arg; void *arg;
void (*cb)(void *arg, int fd, int events); void (*cb)(void *arg, int fd, int events);
} io; } io;
/* Inetd Plugin, stdio used as client socket.
* @type argument will be either SOCK_DGRAM or SOCK_STREAM */
struct {
int (*cmd)(int type);
} inetd;
char *depends[PLUGIN_DEP_MAX]; /* List of other .name's this depends on. */
} plugin_t; } plugin_t;
/* Used by svc.h */
typedef struct plugin_svc plugin_svc_t;
/* Public plugin API */ /* Public plugin API */
int plugin_io_init (plugin_t *plugin);
int plugin_register (plugin_t *plugin); int plugin_register (plugin_t *plugin);
int plugin_unregister (plugin_t *plugin); int plugin_unregister (plugin_t *plugin);
/* Helper API */
plugin_t *plugin_find (char *name);
#endif /* FINIT_PLUGIN_H_ */ #endif /* FINIT_PLUGIN_H_ */
/** /**
* Local Variables: * Local Variables:
* version-control: t
* indent-tabs-mode: t * indent-tabs-mode: t
* c-file-style: "linux" * c-file-style: "linux"
* End: * End:
+4
View File
@@ -0,0 +1,4 @@
/*.la
/*.lo
/.deps/*
/.libs/*
-35
View File
@@ -1,35 +0,0 @@
# Plugin based services architecture for finit -*-Makefile-*-
CFLAGS = -fPIC -g -Os
CPPFLAGS += -I..
LDFLAGS = -shared
PLUGINS ?= initctl.so alsa-utils.so bootmisc.so dbus.so hwclock.so \
resolvconf.so urandom.so x11-common.so
DEPS = $(addprefix .,$(PLUGINS:.so=.d))
include ../common.mk
all: $(PLUGINS)
clean:
-@$(RM) $(PLUGINS) *.o
distclean: clean
-@$(RM) $(JUNK) $(DEPS)
install: all
@install -d $(DESTDIR)$(plugindir)
@for plugin in $(PLUGINS); do \
echo " INSTALL $(DESTDIR)$(plugindir)/$$plugin"; \
$(STRIPINST) $$plugin $(DESTDIR)$(plugindir)/$$plugin; \
done
uninstall:
-@for plugin in $(PLUGINS); do \
echo " RM $(DESTDIR)$(plugindir)/$$plugin"; \
rm $(DESTDIR)$(plugindir)/$$plugin 2>/dev/null; \
done
-@rmdir $(DESTDIR)$(plugindir) 2>/dev/null
ifneq ($(MAKECMDGOALS),clean)
-include $(DEPS)
endif
+108
View File
@@ -0,0 +1,108 @@
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 procps.c tty.c urandom.c
if BUILD_ALSA_UTILS_PLUGIN
libplug_la_SOURCES += alsa-utils.c
endif
if BUILD_DBUS_PLUGIN
libplug_la_SOURCES += dbus.c
endif
if INETD
if BUILD_INETD_ECHO_PLUGIN
libplug_la_SOURCES += echo.c
endif
if BUILD_INETD_CHARGEN_PLUGIN
libplug_la_SOURCES += chargen.c
endif
if BUILD_INETD_DAYTIME_PLUGIN
libplug_la_SOURCES += daytime.c
endif
if BUILD_INETD_DISCARD_PLUGIN
libplug_la_SOURCES += discard.c
endif
if BUILD_INETD_TIME_PLUGIN
libplug_la_SOURCES += time.c
endif
endif
if BUILD_LOST_PLUGIN
libplug_la_SOURCES += lost.c
endif
if BUILD_NETLINK_PLUGIN
libplug_la_SOURCES += netlink.c
endif
if BUILD_RESOLVCONF_PLUGIN
libplug_la_SOURCES += resolvconf.c
endif
else
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
endif
if BUILD_DBUS_PLUGIN
pkglib_LTLIBRARIES += dbus.la
endif
if INETD
if BUILD_INETD_ECHO_PLUGIN
pkglib_LTLIBRARIES += echo.la
endif
if BUILD_INETD_CHARGEN_PLUGIN
pkglib_LTLIBRARIES += chargen.la
endif
if BUILD_INETD_DAYTIME_PLUGIN
pkglib_LTLIBRARIES += daytime.la
endif
if BUILD_INETD_DISCARD_PLUGIN
pkglib_LTLIBRARIES += discard.la
endif
if BUILD_INETD_TIME_PLUGIN
pkglib_LTLIBRARIES += time.la
endif
endif
if BUILD_LOST_PLUGIN
pkglib_LTLIBRARIES += lost.la
endif
if BUILD_NETLINK_PLUGIN
pkglib_LTLIBRARIES += netlink.la
endif
if BUILD_RESOLVCONF_PLUGIN
pkglib_LTLIBRARIES += resolvconf.la
endif
if BUILD_X11_COMMON_PLUGIN
pkglib_LTLIBRARIES += x11-common.la
endif
# Clean up .la files installed by libtool despite being in -module mode
install-exec-hook:
@(cd $(DESTDIR)$(pkglibdir) && $(RM) $(pkglib_LTLIBRARIES))
uninstall-hook:
@(cd $(DESTDIR)$(pkglibdir) && for file in $(pkglib_LTLIBRARIES); do $(RM) `basename $$file .la`.so; done)
endif
+18 -15
View File
@@ -1,6 +1,6 @@
/* Save and restore ALSA sound settings using alsactl /* Save and restore ALSA sound settings using alsactl
* *
* Copyright (c) 2012 Joachim Nilsson <troglobit@gmail.com> * Copyright (c) 2012-2016 Joachim Nilsson <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -21,29 +21,33 @@
* THE SOFTWARE. * THE SOFTWARE.
*/ */
#include "finit.h" #include <lite/lite.h>
#include "helpers.h" #include "../finit.h"
#include "plugin.h" #include "../helpers.h"
#include "../plugin.h"
#define ALSACTL "/usr/sbin/alsactl"
static void save(void *UNUSED(arg)) static void save(void *UNUSED(arg))
{ {
_d("Saving system clock to RTC ..."); if (fexist(ALSACTL)) {
run_interactive("/usr/sbin/alsactl store > /dev/null 2>&1", "Saving sound settings"); _d("Saving sound settings ...");
run_interactive(ALSACTL " -g store", "Saving sound settings");
}
} }
static void restore(void *UNUSED(arg)) static void restore(void *UNUSED(arg))
{ {
_d("Restoring system clock from RTC ..."); if (fexist(ALSACTL)) {
run_interactive("/usr/sbin/alsactl restore > /dev/null 2>&1", "Restoring sound settings"); _d("Restoring sound settings ...");
run_interactive(ALSACTL " -g restore", "Restoring sound settings");
}
} }
static plugin_t plugin = { static plugin_t plugin = {
.hook[HOOK_BASEFS_UP] = { .name = __FILE__,
.cb = restore .hook[HOOK_BASEFS_UP] = { .cb = restore },
}, .hook[HOOK_SHUTDOWN] = { .cb = save }
.hook[HOOK_SHUTDOWN] = {
.cb = save
}
}; };
PLUGIN_INIT(plugin_init) PLUGIN_INIT(plugin_init)
@@ -59,7 +63,6 @@ PLUGIN_EXIT(plugin_exit)
/** /**
* Local Variables: * Local Variables:
* version-control: t
* indent-tabs-mode: t * indent-tabs-mode: t
* c-file-style: "linux" * c-file-style: "linux"
* End: * End:
+138 -24
View File
@@ -1,6 +1,6 @@
/* Setup necessary files for UTMP, tracking logins /* Setup necessary system files for, e.g. UTMP (tracking logins)
* *
* Copyright (c) 2012 Joachim Nilsson <troglobit@gmail.com> * Copyright (c) 2012-2016 Joachim Nilsson <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -21,46 +21,161 @@
* THE SOFTWARE. * THE SOFTWARE.
*/ */
#include <ftw.h>
#include <mntent.h>
#include <string.h> #include <string.h>
#include <utmp.h> #include <lite/lite.h>
#include "finit.h" #include "../config.h"
#include "helpers.h" #include "../finit.h"
#include "plugin.h" #include "../helpers.h"
#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
*/
static void setup(void *UNUSED(arg)) static void setup(void *UNUSED(arg))
{ {
#ifdef RUNLEVEL int gid;
struct utmp entry;
#endif
/* 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);
makedir("/var/lib/misc", 0755);
makedir("/var/lib/alarm", 0755);
makedir("/var/lib/urandom",0755);
if (fisdir("/run")) {
_d("System with new /run tmpfs ...");
makedir("/run/lock", 1777);
symlink("/run/lock", "/var/lock");
symlink("/run", "/var/run");
symlink("/dev/shm", "/run/shm");
} else {
makedir("/var/lock", 1777);
makedir("/var/run", 0755);
}
makedir("/var/log", 0755);
makedir("/var/mail", 0755);
makedir("/var/opt", 0755);
makedir("/var/spool", 0755);
makedir("/var/spool/cron", 0755);
makedir("/var/tmp", 0755);
makedir("/var/empty", 0755);
/*
* If /etc/group or "utmp" group is missing,
* default to "root"/"wheel" group
*/
_d("Setting up necessary UTMP files ..."); _d("Setting up necessary UTMP files ...");
touch("/var/run/utmp"); gid = getgroup("utmp");
chown("/var/run/utmp", 0, getgroup("utmp")); if (gid < 0)
chmod("/var/run/utmp", 0664); gid = 0;
#ifdef RUNLEVEL /*
memset(&entry, 0, sizeof(struct utmp)); * UTMP actually needs multiple db files
entry.ut_type = RUN_LVL; */
entry.ut_pid = '0' + RUNLEVEL; create("/var/run/utmp", 0644, 0, gid); /* Currently logged in */
setutent(); create("/var/log/wtmp", 0644, 0, gid); /* Login history */
pututline(&entry); create("/var/log/btmp", 0600, 0, gid); /* Failed logins */
endutent(); create("/var/log/lastlog", 0644, 0, gid);
#endif
/* Set BOOT_TIME UTMP entry */
utmp_set_boot();
#ifdef TOUCH_ETC_NETWORK_RUN_IFSTATE #ifdef TOUCH_ETC_NETWORK_RUN_IFSTATE
touch("/etc/network/run/ifstate"); touch("/etc/network/run/ifstate");
#else #else
remove("/etc/network/run/ifstate"); erase("/etc/network/run/ifstate");
#endif #endif
_d("Setting up misc files ..."); _d("Setting up misc files ...");
mkdir("/var/run/sshd", 01755); /* OpenSSH */ makedir("/var/run/network",0755); /* Needed by Debian/Ubuntu ifupdown */
mkfifo("/dev/xconsole", 0640); /* sysklogd */ makedir("/var/run/lldpd", 0755); /* Needed by lldpd */
makedir("/var/run/pluto", 0755); /* Needed by Openswan */
makedir("/var/run/quagga", 0755); /* Needed by Quagga */
makedir("/var/log/quagga", 0755); /* Needed by Quagga */
makedir("/var/run/sshd", 01755); /* OpenSSH */
makefifo("/dev/xconsole", 0640); /* sysklogd */
chown("/dev/xconsole", 0, getgroup("tty")); chown("/dev/xconsole", 0, getgroup("tty"));
umask(022);
} }
static plugin_t plugin = { static plugin_t plugin = {
.name = __FILE__,
.hook[HOOK_BASEFS_UP] = { .hook[HOOK_BASEFS_UP] = {
.cb = setup .cb = setup
}, },
@@ -78,7 +193,6 @@ PLUGIN_EXIT(plugin_exit)
/** /**
* Local Variables: * Local Variables:
* version-control: t
* indent-tabs-mode: t * indent-tabs-mode: t
* c-file-style: "linux" * c-file-style: "linux"
* End: * End:
+120
View File
@@ -0,0 +1,120 @@
/* Optional inetd plugin for the Character Generator Protocol, RFC 864
*
* 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 <arpa/inet.h>
#include <unistd.h> /* STDIN_FILENO */
#include <sys/socket.h>
#include "../plugin.h"
#define NAME "chargen"
#define PATTERN "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ "
static char *generator(char *buf, size_t buflen)
{
size_t num, len, width = 72;
static size_t pos = 0;
const char pattern[] = PATTERN;
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 = width;
if (num + 3 > buflen)
num = buflen - 3;
len = 0;
}
strncpy(buf, &pattern[pos], num--);
if (len++)
strncpy(&buf[num], pattern, len);
strlcat(buf, "\r\n", width);
if (++pos >= sizeof(pattern) - 1)
pos = 0;
return buf;
}
static int recv_peer(int sd, char *buf, ssize_t len, struct sockaddr *sa, socklen_t *sa_len)
{
len = recvfrom(sd, buf, len, MSG_DONTWAIT, sa, sa_len);
if (-1 == len)
return -1; /* On error, close connection. */
if (inetd_check_loop(sa, *sa_len, NAME))
return -1;
return 0;
}
static int send_peer(int sd, char *buf, ssize_t len, struct sockaddr *sa, socklen_t sa_len)
{
char *pattern = generator(buf, len);
return sendto(sd, pattern, strlen(pattern), MSG_DONTWAIT, sa, sa_len);
}
static int cb(int UNUSED(type))
{
int sd = STDIN_FILENO;
char buf[BUFSIZ];
struct sockaddr_storage sa;
socklen_t sa_len = sizeof(sa);
if (recv_peer(sd, buf, sizeof(buf), (struct sockaddr *)&sa, &sa_len))
return -1;
return send_peer(sd, buf, sizeof(buf), (struct sockaddr *)&sa, sa_len);
}
static plugin_t plugin = {
.name = NAME, /* Must match the inetd /etc/services entry */
.inetd = {
.cmd = cb
},
};
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:
*/
+102
View File
@@ -0,0 +1,102 @@
/* Optional inetd plugin for Daytime Protocol, RFC 867
*
* 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 <arpa/inet.h>
#include <time.h>
#include <unistd.h> /* STDIN_FILENO */
#include <sys/socket.h>
#include "../plugin.h"
#define NAME "daytime"
static char *daytime(char *buf, size_t len)
{
time_t t;
struct tm *tmp;
t = time(NULL);
tmp = localtime(&t);
memset(buf, 0, len);
strftime(buf, len, "%a, %B %d, %Y %T-%Z", tmp);
return buf;
}
static int recv_peer(int sd, char *buf, ssize_t len, struct sockaddr *sa, socklen_t *sa_len)
{
len = recvfrom(sd, buf, sizeof(buf), MSG_DONTWAIT, sa, sa_len);
if (-1 == len)
return -1; /* On error, close connection. */
if (inetd_check_loop(sa, *sa_len, NAME))
return -1;
return 0;
}
static int send_peer(int sd, char *buf, ssize_t len, struct sockaddr *sa, socklen_t sa_len)
{
char *now = daytime(buf, len);
return sendto(sd, now, strlen(now), MSG_DONTWAIT, sa, sa_len);
}
static int cb(int UNUSED(type))
{
int sd = STDIN_FILENO;
char buf[BUFSIZ];
struct sockaddr_storage sa;
socklen_t sa_len = sizeof(sa);
if (recv_peer(sd, buf, sizeof(buf), (struct sockaddr *)&sa, &sa_len))
return -1;
return send_peer(sd, buf, sizeof(buf), (struct sockaddr *)&sa, sa_len);
}
static plugin_t plugin = {
.name = NAME, /* Must match the inetd /etc/services entry */
.inetd = {
.cmd = cb
}
};
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:
*/
+17 -9
View File
@@ -21,26 +21,35 @@
* THE SOFTWARE. * THE SOFTWARE.
*/ */
#include "finit.h" #include <sys/types.h>
#include "helpers.h" #include <lite/lite.h>
#include "plugin.h"
#include "../finit.h"
#include "../config.h"
#include "../helpers.h"
#include "../plugin.h"
static void setup(void *UNUSED(arg)) static void setup(void *UNUSED(arg))
{ {
#ifdef USE_MESSAGE_BUS umask(0);
_d("Starting D-Bus ..."); _d("Starting D-Bus ...");
mkdir("/var/run/dbus", 0755); makedir("/var/run/dbus", 0755);
mkdir("/var/lock/subsys/messagebus", 0755); makedir("/var/lock/subsys", 0755);
makedir("/var/lock/subsys/messagebus", 0755);
run("dbus-uuidgen --ensure"); run("dbus-uuidgen --ensure");
remove("/var/run/dbus/pid"); erase("/var/run/dbus/pid");
run_interactive("dbus-daemon --system", "Starting D-Bus"); run_interactive("dbus-daemon --system", "Starting D-Bus");
#endif
umask(022);
} }
static plugin_t plugin = { static plugin_t plugin = {
.name = __FILE__,
.hook[HOOK_NETWORK_UP] = { .hook[HOOK_NETWORK_UP] = {
.cb = setup .cb = setup
}, },
.depends = { "bootmisc", },
}; };
PLUGIN_INIT(plugin_init) PLUGIN_INIT(plugin_init)
@@ -55,7 +64,6 @@ PLUGIN_EXIT(plugin_exit)
/** /**
* Local Variables: * Local Variables:
* version-control: t
* indent-tabs-mode: t * indent-tabs-mode: t
* c-file-style: "linux" * c-file-style: "linux"
* End: * End:
+67
View File
@@ -0,0 +1,67 @@
/* Optional inetd plugin for the Discard Protocol, RFC 863
*
* 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 <arpa/inet.h>
#include <unistd.h> /* STDIN_FILENO */
#include <sys/socket.h>
#include "../plugin.h"
static int cb(int UNUSED(type))
{
int sd = STDIN_FILENO;
char buf[BUFSIZ];
ssize_t len;
struct sockaddr_storage sa;
socklen_t sa_len = sizeof(sa);
len = recvfrom(sd, buf, sizeof(buf), MSG_DONTWAIT, (struct sockaddr *)&sa, &sa_len);
if (-1 == len)
return -1; /* On error, close connection. */
return 0;
}
static plugin_t plugin = {
.name = "discard", /* Must match the inetd /etc/services entry */
.inetd = {
.cmd = cb
},
};
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:
*/
+81
View File
@@ -0,0 +1,81 @@
/* Optional inetd plugin for the Echo Protocol, RFC 862
*
* 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 <arpa/inet.h>
#include <unistd.h> /* STDIN_FILENO */
#include <sys/socket.h>
#include "../plugin.h"
#define NAME "echo"
static int recv_peer(int sd, char *buf, ssize_t len, struct sockaddr *sa, socklen_t *sa_len)
{
len = recvfrom(sd, buf, sizeof(buf), MSG_DONTWAIT, sa, sa_len);
if (-1 == len)
return -1; /* On error, close connection. */
if (inetd_check_loop(sa, *sa_len, NAME))
return -1;
return len;
}
static int cb(int UNUSED(type))
{
int sd = STDIN_FILENO;
char buf[BUFSIZ];
ssize_t len;
struct sockaddr_storage sa;
socklen_t sa_len = sizeof(sa);
len = recv_peer(sd, buf, sizeof(buf), (struct sockaddr *)&sa, &sa_len);
if (-1 == len)
return -1; /* On error, close connection. */
return sendto(sd, buf, len, MSG_DONTWAIT, (struct sockaddr *)&sa, sa_len);
}
static plugin_t plugin = {
.name = NAME, /* Must match the inetd /etc/services entry */
.inetd = {
.cmd = cb
},
};
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:
*/
+10 -6
View File
@@ -21,23 +21,28 @@
* THE SOFTWARE. * THE SOFTWARE.
*/ */
#include "finit.h" #include <lite/lite.h>
#include "helpers.h"
#include "plugin.h" #include "../finit.h"
#include "../helpers.h"
#include "../plugin.h"
static void save(void *UNUSED(arg)) static void save(void *UNUSED(arg))
{ {
_d("Saving system clock to RTC ..."); _d("Saving system clock to RTC ...");
run_interactive("/sbin/hwclock --systohc --utc", "Saving system time (UTC) to RTC"); /* -w,--systohc, -u,--utc */
run_interactive("/sbin/hwclock -w -u", "Saving system time (UTC) to RTC");
} }
static void restore(void *UNUSED(arg)) static void restore(void *UNUSED(arg))
{ {
_d("Restoring system clock from RTC ..."); _d("Restoring system clock from RTC ...");
run_interactive("/sbin/hwclock --hctosys --utc", "Restoring system clock (UTC) from RTC"); /* -s,--hctosys, -u,--utc */
run_interactive("/sbin/hwclock -s -u", "Restoring system clock (UTC) from RTC");
} }
static plugin_t plugin = { static plugin_t plugin = {
.name = __FILE__,
.hook[HOOK_BASEFS_UP] = { .hook[HOOK_BASEFS_UP] = {
.cb = restore .cb = restore
}, },
@@ -58,7 +63,6 @@ PLUGIN_EXIT(plugin_exit)
/** /**
* Local Variables: * Local Variables:
* version-control: t
* indent-tabs-mode: t * indent-tabs-mode: t
* c-file-style: "linux" * c-file-style: "linux"
* End: * End:
+139 -63
View File
@@ -1,7 +1,7 @@
/* Optional /dev/initctl FIFO monitor /* Optional /dev/initctl FIFO monitor, for receiving commands from telinit
* *
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com> * Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
* Copyright (c) 2008-2012 Joachim Nilsson <troglobit@gmail.com> * Copyright (c) 2008-2015 Joachim Nilsson <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -22,85 +22,162 @@
* THE SOFTWARE. * THE SOFTWARE.
*/ */
#include "../config.h" /* Generated by configure script */
#include <errno.h> #include <errno.h>
#include <fcntl.h> /* O_RDONLY et al */ #include <fcntl.h> /* O_RDONLY et al */
#include <signal.h> #include <signal.h>
#include <string.h> #include <string.h>
#include <unistd.h> /* read() */
#include <sys/stat.h>
#include <lite/lite.h>
#include "helpers.h" #include "../finit.h"
#include "plugin.h" #include "../conf.h"
#include "../helpers.h"
#include "../plugin.h"
#include "../sig.h"
#include "../service.h"
#define INIT_MAGIC 0x03091969 static void parse(void *arg, int fd, int events);
#define INIT_CMD_RUNLVL 1 static void setup(void *arg);
struct init_request {
int magic; /* Magic number */
int cmd; /* What kind of request */
int runlevel; /* Runlevel to change to */
int sleeptime; /* Time between TERM and KILL */
char data[368];
};
/* Standard reboot/shutdown utilities talk to init using /dev/initctl.
* We should check if the fifo was recreated and reopen it.
*/
static void read_initctl(void *UNUSED(arg), int fd, int UNUSED(events))
{
struct init_request request;
_d("Receiving request on %s...", FINIT_FIFO);
while (1) {
ssize_t len = read(fd, &request, sizeof(request));
if (-1 == len) {
_d("Error %d", errno);
break; /* Probably EAGAIN */
}
if (request.magic != INIT_MAGIC)
continue;
_d("Magic OK...");
if (request.cmd == INIT_CMD_RUNLVL) {
switch (request.runlevel) {
case '0':
_d("Halting system (SIGUSR2)");
do_shutdown(SIGUSR2);
break;
case '6':
_d("Rebooting system (SIGUSR1)");
do_shutdown(SIGUSR1);
break;
default:
_d("Unsupported runlevel: %d", request.runlevel);
break;
}
} else {
_d("Unsupported cmd: %d", request.cmd);
}
}
}
static plugin_t plugin = { static plugin_t plugin = {
.name = __FILE__,
.io = { .io = {
.cb = read_initctl, .cb = parse,
.flags = PLUGIN_IO_READ, .flags = PLUGIN_IO_READ,
}, },
.hook[HOOK_BASEFS_UP] = {
.cb = setup
},
.depends = { "bootmisc", },
}; };
PLUGIN_INIT(plugin_init) static void fifo_open(void)
{ {
_d("Setting up %s", FINIT_FIFO); plugin.io.fd = open(FINIT_FIFO, O_RDWR | O_NONBLOCK | O_CLOEXEC);
mkfifo(FINIT_FIFO, 0600);
plugin.io.fd = open(FINIT_FIFO, O_RDONLY | O_NONBLOCK);
if (-1 == plugin.io.fd) { if (-1 == plugin.io.fd) {
_e("Failed opening %s FIFO, error %d: %s", FINIT_FIFO, errno, strerror(errno)); _e("Failed opening %s FIFO, error %d: %s", FINIT_FIFO, errno, strerror(errno));
return; return;
} }
}
/*
* We only handle INIT_HALT for differentiating between halt/poweroff
*/
static void set_env(char *data)
{
const char *var = "INIT_HALT";
if (strncmp(data, var, strlen(var)))
return;
data += strlen(var);
/*
* No value means unset env, in this case cancel shutdown.
*/
if (data[0] == 0) {
halt = SHUT_DEFAULT;
/* XXX: Cancel timer here, when we get support for timed shutdown */
return;
}
if (string_match(data, "=POWERDOWN"))
halt = SHUT_OFF;
if (string_match(data, "=HALT"))
halt = SHUT_HALT;
/* Now we wait for runlevel change, or cancelled shutdown */
}
/*
* 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) {
ssize_t len = read(fd, &rq, sizeof(rq));
if (len <= 0) {
if (-1 == len) {
if (EINTR == errno)
continue;
if (EAGAIN == errno)
break;
_e("Failed reading initctl request, error %d: %s", errno, strerror(errno));
}
_d("Nothing to do, bailing out.");
break;
}
if (rq.magic != INIT_MAGIC || len != sizeof(rq)) {
_e("Invalid initctl request.");
break;
}
switch (rq.cmd) {
case INIT_CMD_RUNLVL:
switch (rq.runlevel) {
case 's':
case 'S':
rq.runlevel = '1';
/* Fall through to regular processing */
case '0'...'9':
_d("Setting new runlevel %c", rq.runlevel);
lvl = rq.runlevel - '0';
if (lvl == 6)
halt = SHUT_REBOOT;
service_runlevel(lvl);
break;
default:
_d("Unsupported runlevel: %d", rq.runlevel);
break;
}
break;
case INIT_CMD_RELOAD:
service_reload_dynamic();
break;
case INIT_CMD_SETENV:
set_env(rq.data);
break;
default:
_d("Unsupported cmd: %d", rq.cmd);
break;
}
}
close(fd);
fifo_open();
}
/* Must run after the base FS is up, needs /run, or /var/run */
static void setup(void *UNUSED(arg))
{
_d("Setting up %s", FINIT_FIFO);
makefifo(FINIT_FIFO, 0600);
fifo_open();
plugin_io_init(&plugin);
}
PLUGIN_INIT(plugin_init)
{
plugin_register(&plugin); plugin_register(&plugin);
} }
@@ -111,7 +188,6 @@ PLUGIN_EXIT(plugin_exit)
/** /**
* Local Variables: * Local Variables:
* version-control: t
* indent-tabs-mode: t * indent-tabs-mode: t
* c-file-style: "linux" * c-file-style: "linux"
* End: * End:
+60
View File
@@ -0,0 +1,60 @@
/* Example HOOK_SVC_LOST plugin, very noisy do not use as-is!
*
* 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 "../finit.h"
#include "../svc.h"
#include "../plugin.h"
static void lost_pid(void *arg)
{
pid_t pid = (uintptr_t)arg;
svc_t *svc;
svc = svc_find_by_pid(pid);
if (!svc)
return;
logit(LOG_INFO, "Lost PID %u, svc %s", pid, svc->cmd);
}
static plugin_t plugin = {
.name = __FILE__,
.hook[HOOK_SVC_LOST] = { .cb = lost_pid },
};
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:
*/
+233
View File
@@ -0,0 +1,233 @@
/* Netlink plugin for IFUP/IFDN and GW events
*
* Copyright (C) 2009-2011 Mårten Wikström <marten.wikstrom@keystream.se>
* Copyright (C) 2009-2015 Joachim Nilsson <troglobit@gmail.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <arpa/inet.h>
#include <errno.h>
#include <net/if.h> /* IFNAMSIZ */
#include <sys/socket.h>
#include <linux/types.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <unistd.h>
#include "../finit.h"
#include "../cond.h"
#include "../helpers.h"
#include "../plugin.h"
static int nlmsg_validate(struct nlmsghdr *nh, size_t len)
{
if (!NLMSG_OK(nh, len))
return 1;
if (nh->nlmsg_type == NLMSG_DONE) {
_d("Done with netlink messages.");
return 1;
}
if (nh->nlmsg_type == NLMSG_ERROR) {
_d("Netlink reports error.");
return 1;
}
return 0;
}
static void nl_route(struct nlmsghdr *nlmsg)
{
struct rtmsg *r;
struct rtattr *a;
int la;
int gw = 0, dst = 0, mask = 0, idx = 0;
if (nlmsg->nlmsg_len < NLMSG_LENGTH(sizeof(struct rtmsg))) {
_e("Packet too small or truncated!");
return;
}
r = NLMSG_DATA(nlmsg);
a = RTM_RTA(r);
la = RTM_PAYLOAD(nlmsg);
while (RTA_OK(a, la)) {
void *data = RTA_DATA(a);
switch (a->rta_type) {
case RTA_GATEWAY:
gw = *((int *)data);
//_d("GW: 0x%04x", gw);
break;
case RTA_DST:
dst = *((int *)data);
mask = r->rtm_dst_len;
//_d("MASK: 0x%04x", mask);
break;
case RTA_OIF:
idx = *((int *)data);
//_d("IDX: 0x%04x", idx);
break;
}
a = RTA_NEXT(a, la);
}
if ((!dst && !mask) && (gw || idx)) {
if (nlmsg->nlmsg_type == RTM_DELROUTE)
cond_clear("net/route/default");
else
cond_set("net/route/default");
}
}
static void nl_link(struct nlmsghdr *nlmsg)
{
int la;
char ifname[IFNAMSIZ + 1];
struct rtattr *a;
struct ifinfomsg *i;
if (nlmsg->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifinfomsg))) {
_e("Packet too small or truncated!");
return;
}
i = NLMSG_DATA(nlmsg);
a = (struct rtattr *)((char *)i + NLMSG_ALIGN(sizeof(struct ifinfomsg)));
la = NLMSG_PAYLOAD(nlmsg, sizeof(struct ifinfomsg));
while (RTA_OK(a, la)) {
if (a->rta_type == IFLA_IFNAME) {
char msg[MAX_ARG_LEN];
strlcpy(ifname, RTA_DATA(a), sizeof(ifname));
switch (nlmsg->nlmsg_type) {
case RTM_NEWLINK:
/*
* New interface has appearad, or interface flags has changed.
* Check ifi_flags here to see if the interface is UP/DOWN
*/
if (i->ifi_change & IFF_UP) {
snprintf(msg, sizeof(msg), "net/%s/up", ifname);
if (i->ifi_flags & IFF_UP)
cond_set(msg);
else
cond_clear(msg);
if (string_compare("lo", ifname)) {
snprintf(msg, sizeof(msg), "net/%s/exist", ifname);
cond_set(msg);
}
} else {
snprintf(msg, sizeof(msg), "net/%s/exist", ifname);
cond_set(msg);
}
break;
case RTM_DELLINK:
/* NOTE: Interface has dissapeared, not link down ... */
snprintf(msg, sizeof(msg), "net/%s/exist", ifname);
cond_clear(msg);
break;
case RTM_NEWADDR:
_d("%s: New Address", ifname);
break;
case RTM_DELADDR:
_d("%s: Deconfig Address", ifname);
break;
default:
_d("%s: Msg 0x%x", ifname, nlmsg->nlmsg_type);
break;
}
}
a = RTA_NEXT(a, la);
}
}
static void nl_callback(void *UNUSED(arg), int sd, int UNUSED(events))
{
ssize_t len;
static char buf[4096];
struct nlmsghdr *nh;
memset(buf, 0, sizeof(buf));
len = recv(sd, buf, sizeof(buf), 0);
if (len < 0) {
if (errno != EINTR) /* Signal */
_pe("recv()");
return;
}
for (nh = (struct nlmsghdr *)buf; !nlmsg_validate(nh, len); nh = NLMSG_NEXT(nh, len)) {
//_d("Well formed netlink message received. type %d ...", nh->nlmsg_type);
if (nh->nlmsg_type == RTM_NEWROUTE || nh->nlmsg_type == RTM_DELROUTE)
nl_route(nh);
else
nl_link(nh);
}
}
static plugin_t plugin = {
.name = __FILE__,
.io = {
.cb = nl_callback,
.flags = PLUGIN_IO_READ,
},
};
PLUGIN_INIT(plugin_init)
{
int sd;
struct sockaddr_nl sa;
sd = socket(AF_NETLINK, SOCK_RAW | SOCK_NONBLOCK | SOCK_CLOEXEC, NETLINK_ROUTE);
if (sd < 0) {
_pe("socket()");
return;
}
memset(&sa, 0, sizeof(sa));
sa.nl_family = AF_NETLINK;
sa.nl_groups = RTMGRP_IPV4_ROUTE | RTMGRP_LINK; // | RTMGRP_NOTIFY | RTMGRP_IPV4_IFADDR;
sa.nl_pid = getpid();
if (bind(sd, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
_pe("bind()");
close(sd);
return;
}
plugin.io.fd = sd;
plugin_register(&plugin);
}
PLUGIN_EXIT(plugin_exit)
{
plugin_unregister(&plugin);
}
/**
* Local Variables:
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/
+159
View File
@@ -0,0 +1,159 @@
/* Simple pidfile event monitor for the Finit condition engine
*
* Copyright (c) 2015-2016 Tobias Waldekranz <tobias@waldekranz.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 <limits.h>
#include <paths.h>
#include <sys/inotify.h>
#include "../finit.h"
#include "../cond.h"
#include "../helpers.h"
#include "../plugin.h"
struct context {
int fd;
int wd;
};
static void pidfile_callback(void *UNUSED(arg), int fd, int UNUSED(events))
{
static char ev_buf[8 *(sizeof(struct inotify_event) + NAME_MAX + 1) + 1];
static char cond[MAX_ARG_LEN];
struct inotify_event *ev;
ssize_t sz, len;
char *basename;
svc_t *svc;
sz = read(fd, ev_buf, sizeof(ev_buf) - 1);
if (sz <= 0) {
_pe("invalid inotify event");
return;
}
ev_buf[sz] = 0;
for (ev = (void *)ev_buf; sz > (ssize_t)sizeof(*ev);
len = sizeof(*ev) + ev->len, ev = (void *)ev + len, sz -= len) {
/* ev = (void *)(ev + 1) + ev->len, sz -= sizeof(*ev) + ev->len) { */
if (!ev->mask || !strstr(ev->name, ".pid"))
continue;
basename = strtok(ev->name, ".");
if (!basename)
continue;
svc = svc_find_by_nameid(basename, 1);
if (!svc)
continue;
/* TODO FIXME XXX WKZ check that pid is controlled by finit */
_d("%s: match %s", basename, svc->cmd);
snprintf(cond, sizeof(cond), "svc%s", svc->cmd);
if (ev->mask & (IN_CREATE | IN_ATTRIB | IN_MODIFY)) {
svc_started(svc);
cond_set(cond);
} else if (ev->mask & IN_DELETE)
cond_clear(cond);
}
}
/*
* Assert condition only if the service is running, but not if it's
* recently been changed or while it's starting up.
*
* We must wait for the service to create/touch its pidfile.
*/
static void pidfile_reconf(void *_null)
{
static char name[MAX_ARG_LEN];
svc_t *svc;
(void)(_null);
for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) {
if (svc->state == SVC_RUNNING_STATE && !svc_is_changed(svc) && !svc_is_starting(svc)) {
snprintf(name, MAX_ARG_LEN, "svc%s", svc->cmd);
cond_set_path(cond_path(name), COND_ON);
}
}
}
static void pidfile_init(void *arg)
{
struct context *ctx = arg;
ctx->wd = inotify_add_watch(ctx->fd, _PATH_VARRUN,
IN_CREATE | IN_ATTRIB | IN_DELETE | IN_MODIFY);
if (ctx->wd < 0) {
_pe("inotify_add_watch()");
close(ctx->fd);
return;
}
_d("pidfile monitor active");
}
static struct context pidfile_ctx;
/*
* We require /var/run to be set up before calling pidfile_init(),
* so the bootmisc plugin must run first.
*/
static plugin_t plugin = {
.hook[HOOK_BASEFS_UP] = { .arg = &pidfile_ctx, .cb = pidfile_init },
.hook[HOOK_SVC_RECONF] = { .cb = pidfile_reconf },
.io = {
.cb = pidfile_callback,
.flags = PLUGIN_IO_READ,
},
.depends = { "bootmisc", },
};
PLUGIN_INIT(plugin_init)
{
pidfile_ctx.fd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
if (pidfile_ctx.fd < 0) {
_pe("inotify_init()");
return;
}
plugin.io.fd = pidfile_ctx.fd;
plugin_register(&plugin);
}
PLUGIN_EXIT(plugin_exit)
{
inotify_rm_watch(pidfile_ctx.fd, pidfile_ctx.wd);
close(pidfile_ctx.fd);
plugin_unregister(&plugin);
}
/**
* Local Variables:
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/
+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:
*/
+16 -34
View File
@@ -21,53 +21,36 @@
* THE SOFTWARE. * THE SOFTWARE.
*/ */
#include "finit.h" #include <lite/lite.h>
#include "helpers.h"
#include "plugin.h"
#include "../finit.h"
#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)) static void setup(void *UNUSED(arg))
{ {
#ifdef USE_ETC_RESOLVCONF_RUN
DIR *dir;
struct dirent *d;
#endif
_d("Setting up the resolver ..."); _d("Setting up the resolver ...");
#ifdef USE_ETC_RESOLVCONF_RUN mkpath("/etc/resolvconf", 0755);
makepath("/dev/shm/network"); mkpath("/etc/resolvconf/run", 0755);
makepath("/dev/shm/resolvconf/interface"); mkpath("/var/run/resolvconf", 0755);
mkpath("/var/run/resolvconf/interface", 0755);
if ((dir = opendir("/etc/resolvconf/run/interface")) != NULL) {
while ((d = readdir(dir)) != NULL) {
if (isalnum(d->d_name[0]))
continue;
snprintf(line, sizeof(line),
"/etc/resolvconf/run/interface/%s", d->d_name);
unlink(line);
}
closedir(dir);
}
#endif
#ifdef USE_VAR_RUN_RESOLVCONF
makepath("/var/run/resolvconf/interface");
symlink("../../../etc/resolv.conf", "/var/run/resolvconf/resolv.conf");
#endif
#ifdef USE_ETC_RESOLVCONF_RUN
touch("/etc/resolvconf/run/enable-updates"); touch("/etc/resolvconf/run/enable-updates");
chdir("/etc/resolvconf/run/interface"); chdir("/etc/resolvconf/run/interface");
run_parts("/etc/resolvconf/update.d", "-i", NULL); run_parts("/etc/resolvconf/update.d", "-i");
chdir("/"); chdir("/");
#endif /* USE_ETC_RESOLVCONF_RUN */
} }
static plugin_t plugin = { static plugin_t plugin = {
.name = __FILE__,
.hook[HOOK_BASEFS_UP] = { .hook[HOOK_BASEFS_UP] = {
.cb = setup .cb = setup
}, },
.depends = { "bootmisc", },
}; };
PLUGIN_INIT(plugin_init) PLUGIN_INIT(plugin_init)
@@ -82,7 +65,6 @@ PLUGIN_EXIT(plugin_exit)
/** /**
* Local Variables: * Local Variables:
* version-control: t
* indent-tabs-mode: t * indent-tabs-mode: t
* c-file-style: "linux" * c-file-style: "linux"
* End: * End:
+116
View File
@@ -0,0 +1,116 @@
/* Optional inetd plugin for Time Protocol (rdate), RFC 868
*
* Copyright (c) 2015 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 <arpa/inet.h>
#include <time.h>
#include <unistd.h> /* STDIN_FILENO */
#include <sys/socket.h>
#include "../plugin.h"
#define NAME "time"
/* UNIX epoch starts midnight, 1st Jan, 1970 */
#define EPOCH_OFFSET 2208988800ULL
/* Return number of seconds since midnight, 1st Jan, 1900 */
static char *rfctime(char *buf, size_t *len)
{
time_t now;
now = time(NULL);
if ((time_t)-1 == now)
return NULL;
/*
* Account for UNIX epoch offset, and
* convert to network byte order
*/
now += EPOCH_OFFSET;
now = htonl(now);
*len = sizeof(now);
memcpy(buf, &now, *len);
return buf;
}
static int recv_peer(int sd, char *buf, ssize_t len, struct sockaddr *sa, socklen_t *sa_len)
{
len = recvfrom(sd, buf, sizeof(buf), MSG_DONTWAIT, sa, sa_len);
if (-1 == len)
return -1; /* On error, close connection. */
if (inetd_check_loop(sa, *sa_len, NAME))
return -1;
return 0;
}
static int send_peer(int sd, char *buf, ssize_t len, struct sockaddr *sa, socklen_t sa_len)
{
char *now;
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 UNUSED(type))
{
int sd = STDIN_FILENO;
char buf[BUFSIZ];
struct sockaddr_storage sa;
socklen_t sa_len = sizeof(sa);
if (recv_peer(sd, buf, sizeof(buf), (struct sockaddr *)&sa, &sa_len))
return -1; /* On error, close connection. */
return send_peer(sd, buf, sizeof(buf), (struct sockaddr *)&sa, sa_len);
}
static plugin_t plugin = {
.name = NAME, /* Must match the inetd /etc/services entry */
.inetd = {
.cmd = cb
}
};
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:
*/
+103
View File
@@ -0,0 +1,103 @@
/* Optional TTY Watcher, used to catch new TTYs that are discovered, e.g., USB
*
* Copyright (c) 2013 Mattias Walström <lazzer@gmail.com>
* Copyright (c) 2013 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 <errno.h>
#include <fcntl.h> /* O_RDONLY et al */
#include <unistd.h> /* read() */
#include <sys/inotify.h>
#include <sys/stat.h>
#include <lite/lite.h>
#include "../finit.h"
#include "../helpers.h"
#include "../plugin.h"
#include "../tty.h"
static void watcher(void *arg, int fd, int events);
static plugin_t plugin = {
.io = {
.cb = watcher,
.flags = PLUGIN_IO_READ,
},
};
static void setup(void)
{
if (plugin.io.fd)
close(plugin.io.fd);
plugin.io.fd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
if (-1 == plugin.io.fd || inotify_add_watch(plugin.io.fd, "/dev", IN_CREATE | IN_DELETE) < 0)
_pe("Failed starting TTY watcher");
}
static void watcher(void *UNUSED(arg), int fd, int UNUSED(events))
{
int len = 0;
char buf[EVENT_SIZE], name[42];
tty_node_t *entry;
struct inotify_event *notified = (struct inotify_event *)buf;
while ((len = read(fd, buf, sizeof(buf)))) {
if (-1 == len) {
if (errno == EINVAL)
setup();
if (errno == EINTR)
continue;
break; /* Likely EAGAIN */
}
snprintf(name, sizeof(name), "/dev/%s", notified->name);
entry = tty_find(name);
if (entry && tty_enabled(&entry->data, runlevel)) {
if (notified->mask & IN_CREATE)
tty_start(&entry->data);
else if (entry->data.pid)
tty_stop(&entry->data);
}
}
}
PLUGIN_INIT(plugin_init)
{
setup();
plugin_register(&plugin);
}
PLUGIN_EXIT(plugin_exit)
{
if (plugin.io.fd)
close(plugin.io.fd);
plugin_unregister(&plugin);
}
/**
* Local Variables:
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/
+46 -11
View File
@@ -22,28 +22,64 @@
*/ */
#include <unistd.h> #include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/time.h> /* gettimeofday() */
#include <sys/types.h>
#include <lite/lite.h>
#include "finit.h" #include "../config.h"
#include "helpers.h" #include "../finit.h"
#include "plugin.h" #include "../helpers.h"
#include "../plugin.h"
static void setup(void *UNUSED(arg)) static void setup(void *UNUSED(arg))
{ {
#ifdef RANDOMSEED #ifdef RANDOMSEED
copyfile(RANDOMSEED, "/dev/urandom", 0); if (!fexist(RANDOMSEED)) {
unlink(RANDOMSEED); int ret = 1;
FILE *fp;
print_desc("Bootstrapping random seed", NULL);
umask(077);
fp = fopen(RANDOMSEED, "w");
if (fp) {
int iter = 128;
struct timeval tv;
gettimeofday(&tv, NULL);
srandom(tv.tv_sec % 3600);
while (iter--) {
uint32_t i, prng = random();
for (i = 0; i < sizeof(prng); i++)
fputc((prng >> (i * CHAR_BIT)) & UCHAR_MAX, fp);
}
ret = fclose(fp);
}
print_result(ret);
umask(0);
}
print_desc("Initializing random number generator", NULL);
print_result(512 != copyfile(RANDOMSEED, "/dev/urandom", 0, 0));
#endif
}
static void save(void *UNUSED(arg))
{
#ifdef RANDOMSEED
umask(077); umask(077);
copyfile("/dev/urandom", RANDOMSEED, 4096); print_desc("Saving random seed", NULL);
print_result(512 != copyfile("/dev/urandom", RANDOMSEED, 512, 0));
umask(0); umask(0);
#endif #endif
} }
static plugin_t plugin = { static plugin_t plugin = {
.hook[HOOK_BASEFS_UP] = { .name = __FILE__,
.cb = setup .hook[HOOK_BASEFS_UP] = { .cb = setup },
}, .hook[HOOK_SHUTDOWN] = { .cb = save },
.depends = { "bootmisc", }
}; };
PLUGIN_INIT(plugin_init) PLUGIN_INIT(plugin_init)
@@ -58,7 +94,6 @@ PLUGIN_EXIT(plugin_exit)
/** /**
* Local Variables: * Local Variables:
* version-control: t
* indent-tabs-mode: t * indent-tabs-mode: t
* c-file-style: "linux" * c-file-style: "linux"
* End: * End:
+16 -7
View File
@@ -24,10 +24,11 @@
#include <unistd.h> #include <unistd.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <lite/lite.h>
#include "finit.h" #include "../finit.h"
#include "helpers.h" #include "../helpers.h"
#include "plugin.h" #include "../plugin.h"
static void setup(void *UNUSED(arg)) static void setup(void *UNUSED(arg))
{ {
@@ -36,7 +37,9 @@ static void setup(void *UNUSED(arg))
#endif #endif
char line[LINE_SIZE]; char line[LINE_SIZE];
makepath("/var/run/console"); umask(0);
makedir("/var/run/console", 01777);
snprintf(line, sizeof(line), "/var/run/console/%s", username); snprintf(line, sizeof(line), "/var/run/console/%s", username);
touch(line); touch(line);
@@ -48,14 +51,21 @@ static void setup(void *UNUSED(arg))
} }
#endif #endif
mkdir("/tmp/.X11-unix", 01777); makedir("/tmp/.X11-unix", 01777);
mkdir("/tmp/.ICE-unix", 01777); makedir("/tmp/.ICE-unix", 01777);
if (fexist("/sbin/restorecon"))
run("/sbin/restorecon /tmp/.ICE-unix /tmp/.X11-unix");
umask(022);
} }
static plugin_t plugin = { static plugin_t plugin = {
.name = __FILE__,
.hook[HOOK_NETWORK_UP] = { .hook[HOOK_NETWORK_UP] = {
.cb = setup .cb = setup
}, },
.depends = { "bootmisc", }
}; };
PLUGIN_INIT(plugin_init) PLUGIN_INIT(plugin_init)
@@ -70,7 +80,6 @@ PLUGIN_EXIT(plugin_exit)
/** /**
* Local Variables: * Local Variables:
* version-control: t
* indent-tabs-mode: t * indent-tabs-mode: t
* c-file-style: "linux" * c-file-style: "linux"
* End: * End:
+19 -7
View File
@@ -1,7 +1,7 @@
/* Private header file for main finit daemon, not for plugins /* Private header file for main finit daemon, not for plugins
* *
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com> * Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
* Copyright (c) 2008-2012 Joachim Nilsson <troglobit@gmail.com> * Copyright (c) 2008-2013 Joachim Nilsson <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -25,19 +25,31 @@
#ifndef FINIT_PRIVATE_H_ #ifndef FINIT_PRIVATE_H_
#define FINIT_PRIVATE_H_ #define FINIT_PRIVATE_H_
#include "svc.h"
#include "plugin.h" #include "plugin.h"
/* plugin.c */ /*
void run_hooks (hook_point_t no); * Main loop context
void run_services (void); */
int load_plugins (char *path); uev_ctx_t *ctx;
void io_monitor (void);
int api_init (uev_ctx_t *ctx);
int api_exit (void);
int client (int argc, char *argv[]);
void service_monitor (pid_t lost);
void plugin_run_hook (hook_point_t no, void *arg);
void plugin_run_hooks (hook_point_t no);
int plugin_init (uev_ctx_t *ctx, char *path);
void plugin_exit (void);
#endif /* FINIT_PRIVATE_H_ */ #endif /* FINIT_PRIVATE_H_ */
/** /**
* Local Variables: * Local Variables:
* version-control: t
* indent-tabs-mode: t * indent-tabs-mode: t
* c-file-style: "linux" * c-file-style: "linux"
* End: * End:
+206
View File
@@ -0,0 +1,206 @@
/* reboot, halt, poweroff, shutdown, suspend for finit
*
* Copyright (c) 2009-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 <err.h>
#include <getopt.h>
#include <signal.h>
#include <stdio.h>
#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
#endif
typedef enum {
CMD_UNKNOWN = -1,
CMD_REBOOT = 0,
CMD_HALT,
CMD_POWEROFF,
CMD_SUSPEND,
} cmd_t;
static cmd_t cmd = CMD_UNKNOWN;
static char *msg = NULL;
static void translate(void)
{
if (cmd == CMD_UNKNOWN) {
if (!strcmp(prognm, "halt") || !strcmp(prognm, "shutdown"))
cmd = CMD_HALT;
else if (!strcmp(prognm, "poweroff"))
cmd = CMD_POWEROFF;
else if (!strcmp(prognm, "suspend"))
cmd = CMD_SUSPEND;
else
cmd = CMD_REBOOT;
}
switch (cmd) {
case CMD_REBOOT:
msg = "reboot";
break;
case CMD_HALT:
msg = "halt";
break;
case CMD_POWEROFF:
msg = "power-off";
break;
case CMD_SUSPEND:
msg = "suspend";
break;
case CMD_UNKNOWN:
cmd = CMD_REBOOT;
msg = "reboot";
break;
}
}
static int usage(int rc)
{
fprintf(stderr, "Usage: %s [OPTIONS]\n\n"
"Options:\n"
" -h, --help This help text\n"
" -f, --force Force unsafe %s now, do not contact the init system.\n"
" --halt Halt system, regardless of how the command is called.\n"
" -p, --poweroff Power-off system, regardless of how the command is called.\n"
" --reboot Reboot system, regardless of how the command is called.\n"
"\n", prognm, msg);
return rc;
}
int main(int argc, char *argv[])
{
int c, force = 0;
struct option long_options[] = {
{"help", 0, NULL, 'h'},
{"force", 0, NULL, 'f'},
{"halt", 0, NULL, 'H'},
{"poweroff", 0, NULL, 'p'},
{"reboot", 0, NULL, 'r'},
{NULL, 0, NULL, 0}
};
/* Initial command taken from program name */
progname(argv[0]);
translate();
while ((c = getopt_long(argc, argv, "h?fHpr", long_options, NULL)) != EOF) {
switch(c) {
case 'h':
case '?':
return usage(0);
case 'f':
force = 1;
break;
case 'H':
cmd = CMD_HALT;
break;
case 'p':
cmd = CMD_POWEROFF;
break;
case 'r':
cmd = CMD_REBOOT;
break;
default:
return usage(1);
}
}
/* Check for any overrides */
translate();
if (force) {
switch (cmd) {
case CMD_REBOOT:
c = reboot(RB_AUTOBOOT);
break;
case CMD_HALT:
c = reboot(RB_HALT_SYSTEM);
break;
case CMD_POWEROFF:
c = reboot(RB_POWER_OFF);
break;
case CMD_SUSPEND:
c = reboot(RB_SW_SUSPEND);
break;
case CMD_UNKNOWN:
errx(1, "Invalid command");
break;
}
if (c)
warn("Failed forced %s", msg);
else
return 0;
}
switch (cmd) {
case CMD_REBOOT:
c = kill(1, SIGTERM);
break;
case CMD_HALT:
c = kill(1, SIGUSR1);
break;
case CMD_POWEROFF:
c = kill(1, SIGUSR2);
break;
case CMD_SUSPEND:
case CMD_UNKNOWN:
errx(1, "Invalid command");
break;
}
if (c)
err(1, "Failed signalling init to %s", msg);
else
sleep(2);
return 0;
}
/**
* Local Variables:
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/
Executable
+14
View File
@@ -0,0 +1,14 @@
#!/bin/sh
if [ $# -eq 0 ]; then
initctl show
exit 0
fi
if [ $# -lt 2 -o $# -gt 2 ]; then
echo "Usage: service [job# | name] <stop | start | restart | reload>"
exit 1
fi
initctl $2 $1
+1007
View File
File diff suppressed because it is too large Load Diff
+47
View File
@@ -0,0 +1,47 @@
/* Finit service monitor, task starter and generic API for managing svc_t
*
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
* Copyright (c) 2008-2015 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_SERVICE_H_
#define FINIT_SERVICE_H_
#include "svc.h"
void service_runlevel (int newlevel);
int service_register (int type, char *line, time_t mtime, char *username);
void service_unregister (svc_t *svc);
int service_enabled (svc_t *svc);
void service_reload_dynamic (void);
void service_step (svc_t *svc);
void service_step_all (int types);
#endif /* FINIT_SERVICE_H_ */
/**
* Local Variables:
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/
+276 -65
View File
@@ -1,7 +1,7 @@
/* Signal management - Be conservative with what finit responds to! /* Signal management - Be conservative with what finit responds to!
* *
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com> * Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
* Copyright (c) 2008-2012 Joachim Nilsson <troglobit@gmail.com> * Copyright (c) 2008-2014 Joachim Nilsson <troglobit@gmail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -21,101 +21,282 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE. * THE SOFTWARE.
* *
* The standard SysV init only responds to the following signals: * Finit is often used on embedded and small Linux systems with BusyBox.
* SIGHUP * For compatibility with its existing toolset (halt, poweroff, reboot),
* Has the same effect as telinit q. * the following signals have been adopted:
* *
* SIGUSR1 * SIGHUP
* On receipt of this signals, init closes and re-opens its control * Same effect as init/telinit q, reloads *.conf in /etc/finit.d/
* fifo, /dev/initctl. Useful for bootscripts when /dev is remounted.
* *
* SIGINT * SIGUSR1
* Normally the kernel sends this signal to init when CTRL-ALT-DEL is * Calls shutdown hooks, including HOOK_SHUTDOWN, stops all running
* pressed. It activates the ctrlaltdel action. * processes, and unmounts all file systems. Then tells kernel to
* halt. Most people these days want SIGUSR2 though.
* *
* SIGWINCH * (SysV init and systemd use this to re-open their FIFO/D-Bus.)
* The kernel sends this signal when the KeyboardSignal key is hit. *
* It activates the kbrequest action. * 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.
*
* SIGWINCH
* Sent from kernel when the KeyboardSignal key is pressed. Some
* users bind keys, see loadkeys(1), to create consoles on demand.
* Finit currently ignores this signal.
*
* 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.
*/ */
#include <dirent.h>
#include <string.h> /* strerror() */
#include <sys/reboot.h> #include <sys/reboot.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <lite/lite.h>
#include "finit.h" #include "finit.h"
#include "conf.h"
#include "config.h"
#include "helpers.h" #include "helpers.h"
#include "plugin.h" #include "plugin.h"
#include "private.h" #include "private.h"
#include "sig.h" #include "sig.h"
#include "service.h"
#include "utmp-api.h"
static int stopped = 0; /*
* 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;
static uev_t sigstop_watcher, sigtstp_watcher, sigcont_watcher;
void do_shutdown (int sig) 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)
{ {
touch(SYNC_SHUTDOWN); touch(SYNC_SHUTDOWN);
if (sdown) if (sdown)
run_interactive(sdown, "Calling shutdown hook: %s", sdown); run_interactive(sdown, "Calling shutdown hook: %s", sdown);
_d("Sending SIGTERM to all processes."); /* Update UTMP db */
kill(-1, SIGTERM); utmp_set_halt();
sleep(1); /*
/* Call all shutdown hooks, this is the last call before rebooting... */ * Tell all remaining non-monitored processes to exit, give them
run_hooks(HOOK_SHUTDOWN); * some time to exit gracefully, 2 sec is customary.
*/
do_kill(SIGTERM);
do_sleep(2);
do_kill(SIGKILL);
_d("Sending SIGKILL to remaining processes."); /* Exit plugins and API gracefully */
kill(-1, SIGKILL); plugin_exit();
api_exit();
/* Reap 'em */
while (waitpid(-1, NULL, WNOHANG) > 0)
;
/* Close all local non-console descriptors */
for (int fd = 3; fd < 128; fd++)
close(fd);
if (vfork()) {
/*
* Put PID 1 aside and let child perform reboot/halt
* kernel may exit child and we don't want to exit PID 1
* ... causing "aiii killing init" during reboot ...
*/
return;
}
/* Unmount any tmpfs before unmounting swap ... */
unmount_tmpfs();
run("/sbin/swapoff -e -a");
/* ... unmount remaining regular file systems. */
unmount_regular();
/* We sit on / so we must remount it ro, try all the things! */
sync(); sync();
sync(); run("/bin/mount -n -o remount,ro -t dummytype dummydev /");
_d("Unmounting file systems, remounting / read-only."); run("/bin/mount -n -o remount,ro dummydev /");
run("/bin/umount -fa 2>/dev/null"); run("/bin/mount -n -o remount,ro /");
run("/bin/mount -n -o remount,ro / 2>/dev/null");
run("/sbin/swapoff -ea");
_d("%s.", sig == SIGINT || sig == SIGUSR1 ? "Rebooting" : "Halting"); /* Call mdadm to mark any RAID array(s) as clean before halting. */
if (sig == SIGINT || sig == SIGUSR1) 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); reboot(RB_AUTOBOOT);
reboot(RB_POWER_OFF); if (op == SHUT_OFF)
reboot(RB_POWER_OFF);
/* Also fallback if any of the other two fails */
reboot(RB_HALT_SYSTEM);
} }
/* /*
* Shut down on INT USR1 USR2 * Reload .conf files in /etc/finit.d/
*/ */
static void shutdown_handler(int sig, siginfo_t *info, void *UNUSED(ctx)) static void sighup_cb(uev_t *UNUSED(w), void *UNUSED(arg), int UNUSED(events))
{ {
_d("Rebooting on signal %d from %s (PID %d)", _d("...");
sig, pid_get_name(info->si_pid, NULL, 0), info->si_pid); /* INIT_CMD_RELOAD: 'init q', 'initctl reload', and SIGHUP */
service_reload_dynamic();
}
do_shutdown(sig); /*
* SIGINT: Should generate <sys/key/ctrlaltdel> condition, for now reboot
*/
static void sigint_cb(uev_t *UNUSED(w), void *UNUSED(arg), int UNUSED(events))
{
_d("...");
halt = SHUT_REBOOT;
service_runlevel(6);
}
/*
* SIGUSR1: BusyBox style halt
*/
static void sigusr1_cb(uev_t *UNUSED(w), void *UNUSED(arg), int UNUSED(events))
{
_d("...");
halt = SHUT_HALT;
service_runlevel(0);
}
/*
* SIGUSR2: BusyBox style poweroff
*/
static void sigusr2_cb(uev_t *UNUSED(w), void *UNUSED(arg), int UNUSED(events))
{
_d("...");
halt = SHUT_OFF;
service_runlevel(0);
}
/*
* SIGTERM: BusyBox style reboot
*/
static void sigterm_cb(uev_t *UNUSED(w), void *UNUSED(arg), int UNUSED(events))
{
_d("...");
halt = SHUT_REBOOT;
service_runlevel(6);
} }
/* /*
* SIGCHLD: one of our children has died * SIGCHLD: one of our children has died
*/ */
static void chld_handler(int UNUSED(sig), siginfo_t *UNUSED(info), void *UNUSED(ctx)) static void sigchld_cb(uev_t *UNUSED(w), void *UNUSED(arg), int UNUSED(events))
{ {
/* Do nothing, the svc_monitor() is the designated child reaper. */ pid_t pid;
/* Reap all the children! */
do {
pid = waitpid(-1, NULL, WNOHANG);
if (pid > 0) {
_d("Collected child %d", pid);
service_monitor(pid);
}
} while (pid > 0);
} }
/* /*
* SIGSTOP: Paused by user or netflash * SIGSTOP/SIGTSTP: Paused by user or netflash
*/ */
static void sigstop_handler(int sig, siginfo_t *info, void *UNUSED(ctx)) static void sigstop_cb(uev_t *UNUSED(w), void *UNUSED(arg), int UNUSED(events))
{ {
_d("Received SIGSTOP(%d) from %s (PID %d)",
sig, pid_get_name(info->si_pid, NULL, 0), info->si_pid);
touch(SYNC_STOPPED); touch(SYNC_STOPPED);
stopped ++; stopped++;
} }
static void sigcont_handler(int sig, siginfo_t *info, void *UNUSED(ctx))
/*
* SIGCONT: Restart service monitor
*/
static void sigcont_cb(uev_t *UNUSED(w), void *UNUSED(arg), int UNUSED(events))
{ {
_d("Received SIGCONT(%d) from %s (PID %d)",
sig, pid_get_name(info->si_pid, NULL, 0), info->si_pid);
stopped = 0; stopped = 0;
remove(SYNC_STOPPED); erase(SYNC_STOPPED);
} }
/* /*
@@ -129,6 +310,11 @@ int sig_stopped(void)
/* /*
* Inital signal setup - ignore everything but SIGCHLD until we're capable of responding * Inital signal setup - ignore everything but SIGCHLD until we're capable of responding
*/ */
static void chld_handler(int UNUSED(sig), siginfo_t *UNUSED(info), void *UNUSED(ctx))
{
/* NOP */
}
void sig_init(void) void sig_init(void)
{ {
int i; int i;
@@ -140,49 +326,74 @@ void sig_init(void)
SETSIG(sa, SIGCHLD, chld_handler, SA_RESTART); SETSIG(sa, SIGCHLD, chld_handler, SA_RESTART);
} }
/*
* Unblock all signals blocked by finit when starting children
*/
void sig_unblock(void)
{
int i;
sigset_t nmask;
struct sigaction sa;
sigemptyset(&nmask);
sigaddset(&nmask, SIGHUP);
sigaddset(&nmask, SIGCHLD);
sigaddset(&nmask, SIGINT);
sigaddset(&nmask, SIGPWR);
sigaddset(&nmask, SIGSTOP);
sigaddset(&nmask, SIGTSTP);
sigaddset(&nmask, SIGCONT);
sigaddset(&nmask, SIGTERM);
sigaddset(&nmask, SIGUSR1);
sigaddset(&nmask, SIGUSR2);
sigprocmask(SIG_UNBLOCK, &nmask, NULL);
/* Reset signal handlers that were set by the parent process */
for (i = 1; i < NSIG; i++)
DFLSIG(sa, i, 0);
}
/* /*
* Setup limited set of SysV compatible signals to respond to * Setup limited set of SysV compatible signals to respond to
*/ */
void sig_setup(void) void sig_setup(uev_ctx_t *ctx)
{ {
struct sigaction sa; struct sigaction sa;
_d("Setup signals"); _d("Setup signals");
/* Cleanup any stale finit control files */ /* Cleanup any stale finit control files */
remove(SYNC_SHUTDOWN); erase(SYNC_SHUTDOWN);
remove(SYNC_STOPPED); erase(SYNC_STOPPED);
/* Standard SysV init calls ctrl-alt-delete handler */ /* Standard SysV init calls ctrl-alt-delete handler */
SETSIG(sa, SIGINT, shutdown_handler, 0); uev_signal_init(ctx, &sigint_watcher, sigint_cb, NULL, SIGINT);
SETSIG(sa, SIGPWR, shutdown_handler, 0); uev_signal_init(ctx, &sigpwr_watcher, sigint_cb, NULL, SIGPWR);
/* Ignore SIGUSR1/2 for now, only BusyBox init implements them as reboot+halt. */ /* BusyBox init style signals for halt, power-off and reboot. */
// SETSIG2(sa, SIGUSR1, reopen_initctl, 0); uev_signal_init(ctx, &sigusr1_watcher, sigusr1_cb, NULL, SIGUSR1);
// SETSIG2(sa, SIGUSR2, pwrdwn_handler, 0); uev_signal_init(ctx, &sigusr2_watcher, sigusr2_cb, NULL, SIGUSR2);
uev_signal_init(ctx, &sigterm_watcher, sigterm_cb, NULL, SIGTERM);
/* Init must ignore SIGTERM. May otherwise get false SIGTERM in forked children! */
IGNSIG(sa, SIGTERM, 0);
/* Some C APIs may need SIGALRM for implementing timers. */ /* Some C APIs may need SIGALRM for implementing timers. */
IGNSIG(sa, SIGALRM, 0); IGNSIG(sa, SIGALRM, 0);
/* We don't have any /etc/inittab yet, reread finit.conf? */ /* /etc/inittab not supported yet, instead /etc/finit.d/ is scanned for *.conf */
IGNSIG(sa, SIGHUP, 0); uev_signal_init(ctx, &sighup_watcher, sighup_cb, NULL, SIGHUP);
/* After initial bootstrap of Finit we call the service monitor to reap children */
uev_signal_init(ctx, &sigchld_watcher, sigchld_cb, NULL, SIGCHLD);
/* Stopping init is a bit tricky. */ /* Stopping init is a bit tricky. */
SETSIG(sa, SIGSTOP, sigstop_handler, 0); uev_signal_init(ctx, &sigstop_watcher, sigstop_cb, NULL, SIGSTOP);
SETSIG(sa, SIGTSTP, sigstop_handler, 0); uev_signal_init(ctx, &sigtstp_watcher, sigstop_cb, NULL, SIGTSTP);
SETSIG(sa, SIGCONT, sigcont_handler, 0); uev_signal_init(ctx, &sigcont_watcher, sigcont_cb, NULL, SIGCONT);
/* Disable CTRL-ALT-DELETE from kernel, we handle shutdown gracefully with SIGINT, above */
reboot(RB_DISABLE_CAD);
setsid(); setsid();
} }
/** /**
* Local Variables: * Local Variables:
* version-control: t
* indent-tabs-mode: t * indent-tabs-mode: t
* c-file-style: "linux" * c-file-style: "linux"
* End: * End:

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