Compare commits

...
40 Commits
Author SHA1 Message Date
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
32 changed files with 449 additions and 155 deletions
+57 -4
View File
@@ -1,7 +1,58 @@
Change Log Change Log
========== ==========
All notable changes to the project are documented in this file. All relevant changes are documented in this file.
[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 [2.0][] - 2015-09-20
-------------------- --------------------
@@ -19,8 +70,8 @@ introduction of an `initctl` tool.
simply add a `:ID` after the `service` keyword, where `ID` is a unique simply add a `:ID` after the `service` keyword, where `ID` is a unique
instance number for that service. instance number for that service.
service #1 [2345] /sbin/httpd -f -h /http -p 80 -- Web server 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 service :2 [2345] /sbin/httpd -f -h /http -p 8080 -- Old web server
* Another noteworthy new feature is support for starting/stopping * Another noteworthy new feature is support for starting/stopping
services on Netlink events: services on Netlink events:
@@ -152,6 +203,7 @@ The [libuEv] release.
[1.10][] - 2014-11-27 [1.10][] - 2014-11-27
--------------------- ---------------------
Major bug fix release. Major bug fix release.
### Changes ### Changes
@@ -379,7 +431,8 @@ Major bug fix release.
* Initial release * Initial release
[UNRELEASED]: https://github.com/troglobit/finit/compare/1.12...HEAD [UNRELEASED]: https://github.com/troglobit/finit/compare/2.1...HEAD
[2.1]: https://github.com/troglobit/finit/compare/2.0...2.1
[2.0]: https://github.com/troglobit/finit/compare/1.12...2.0 [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.12]: https://github.com/troglobit/finit/compare/1.11...1.12
[1.11]: https://github.com/troglobit/finit/compare/1.10...1.11 [1.11]: https://github.com/troglobit/finit/compare/1.10...1.11
+2 -2
View File
@@ -25,8 +25,8 @@
install-exec install-data install-dev \ install-exec install-data install-dev \
uninstall-exec uninstall-data uninstall-dev uninstall-exec uninstall-data uninstall-dev
#VERSION ?= $(shell git tag -l | tail -1) #VERSION = $(shell git tag -l | tail -1)
VERSION ?= 2.0 VERSION = 2.2
NAME = finit NAME = finit
PKG = $(NAME)-$(VERSION) PKG = $(NAME)-$(VERSION)
DEV = $(NAME)-dev DEV = $(NAME)-dev
+26 -18
View File
@@ -1,5 +1,5 @@
Finit | Fast & Extensible init for Linux Finit ][ Fast & Extensible init for Linux
======================================== =========================================
[![Travis Status]][Travis] [![Coverity Status]][Coverity Scan] [![Travis Status]][Travis] [![Coverity Status]][Coverity Scan]
![Original Finit homepage image](images/finit.jpg "Finit in action!") ![Original Finit homepage image](images/finit.jpg "Finit in action!")
@@ -586,21 +586,23 @@ not return until the given command has fully completed.
Usage: initctl [OPTIONS] <COMMAND> Usage: initctl [OPTIONS] <COMMAND>
Options: Options:
-d, --debug Debug initctl (client)
-v, --verbose Verbose output -v, --verbose Verbose output
-h, --help This help text -h, --help This help text
Commands: Commands:
debug Toggle init daemon debug debug Toggle Finit (daemon) debug
emit <EV> Emit an event: RELOAD, STOP, START, GW emit <EV> Emit an event. Can be a predefined event: RELOAD, STOP,
IFUP:IFNAME, IFDN:IFNAME START, or a custom string to match the event list in a
IFNAME is the interface name, e.g. eth0 service stanza, e.g: GW:UP, IFUP:IFNAME, IFDN:IFNAME,
reload Reload *.conf in /etc/finit.d/, like SIGHUP where IFNAME is the interface name, e.g. eth0
runlevel <0-9> Change runlevel: 0 (halt), 6 (reboot) reload Reload *.conf in /etc/finit.d/ and activate changes
start <JOB#> Start a stopped service runlevel [0-9] Show or set runlevel: 0 halt, 6 reboot
stop <JOB#> Stop a running service status | show Show status of services
restart <JOB#> Restart (stop/start) a running service start <JOB|NAME> Start stopped job or service
reload <JOB#> Reload (SIGHUP) a running service stop <JOB|NAME> Stop/Pause running job or service
status | show List status of all services known to Finit restart <JOB|NAME> Restart (stop/start) job or service
reload <JOB|NAME> Reload (SIGHUP) job or service
version Show Finit version version Show Finit version
``` ```
@@ -610,6 +612,11 @@ their command counterparts. The `reload` command reloads all `*.conf`
files in `/etc/finit.d/` *and* activates the changes, with `emit RELOAD` files in `/etc/finit.d/` *and* activates the changes, with `emit RELOAD`
only the `*.conf` files are reloaded. only the `*.conf` files are reloaded.
**Note:** The `emit STOP` event is more like "prepare" than "stop".
Depending on how the service is declared, `<!>` or not, the service
may be stopped, or skipped to be be sent `SIGHUP` later when `emit
START` is issued.
To achieve the same result as `initctl reload` emit all three events: To achieve the same result as `initctl reload` emit all three events:
```shell ```shell
@@ -643,10 +650,10 @@ started.
The `emit <EV>` command can also be used to emit custom events. In The `emit <EV>` command can also be used to emit custom events. In
fact, the event is a simple string. Declare a list of events in a fact, the event is a simple string. Declare a list of events in a
service stanza: `service … <GW,IFUP:eth0>` to reload (`SIGHUP`) a service stanza: `service … <GW:UP,IFUP:eth0>` to reload (`SIGHUP`) a
service when recieving the `"GW"` or `"IFUP:eth0"` strings. If a service when recieving the `"GW:UP"` or `"IFUP:eth0"` strings. If a
service cannot handle reload and must be stopped-started, simply add an service cannot handle reload and must be stopped-started, simply add an
exclamation mark first: `service … <!GW,IFUP:eth0>`. exclamation mark first: `service … <!GW:UP,IFUP:eth0>`.
The `<!>` notation to a service stanza can be used empty, then it will The `<!>` notation to a service stanza can be used empty, then it will
apply to `reload` and `runlevel` commands. I.e., when a service's apply to `reload` and `runlevel` commands. I.e., when a service's
@@ -706,7 +713,8 @@ switches to configure:
* `--with-plugins=`: List of stock finit plugins to build and install. * `--with-plugins=`: List of stock finit plugins to build and install.
The build system adds `.o` or `.so` extension to the listed plugins The build system adds `.o` or `.so` extension to the listed plugins
depending on the `--enable-static` switch. depending on the `--enable-static` switch. Hence, list the plugins
*without* their extension.
* `--enable-embedded`: Target finit for BusyBox getty and mdev instead * `--enable-embedded`: Target finit for BusyBox getty and mdev instead
of a standard Linux distribution with GNU tools and udev. of a standard Linux distribution with GNU tools and udev.
@@ -754,7 +762,7 @@ First, unpack the archive:
Then configure, build and install: Then configure, build and install:
```shell ```shell
$ ./configure --with-plugins="initctl.so hwclock.so" $ ./configure --with-plugins="initctl hwclock"
$ make $ make
CC finit.o CC finit.o
CC conf.o CC conf.o
+13 -3
View File
@@ -30,6 +30,7 @@
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/un.h> #include <sys/un.h>
#include "config.h"
#include "finit.h" #include "finit.h"
#include "conf.h" #include "conf.h"
#include "helpers.h" #include "helpers.h"
@@ -107,11 +108,17 @@ static int call(int (*action)(svc_t *), char *buf, size_t len)
return result; return result;
} }
static int service_pause(svc_t *svc)
{
return service_stop(svc, SVC_PAUSED_STATE);
}
static int do_start (char *buf, size_t len) { return call(service_start, buf, len); } static int do_start (char *buf, size_t len) { return call(service_start, buf, len); }
static int do_stop (char *buf, size_t len) { return call(service_stop, buf, len); } static int do_pause (char *buf, size_t len) { return call(service_pause, buf, len); }
static int do_reload (char *buf, size_t len) { return call(service_reload, buf, len); } static int do_reload (char *buf, size_t len) { return call(service_reload, buf, len); }
static int do_restart(char *buf, size_t len) { return call(service_restart, 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) static int do_query_inetd(char *buf, size_t len)
{ {
int id = 1; int id = 1;
@@ -135,6 +142,7 @@ static int do_query_inetd(char *buf, size_t len)
return inetd_filter_str(&svc->inetd, buf, len); return inetd_filter_str(&svc->inetd, buf, len);
} }
#endif /* !INETD_DISABLED */
typedef struct { typedef struct {
char *event; char *event;
@@ -255,7 +263,7 @@ static void cb(uev_t *w, void *UNUSED(arg), int UNUSED(events))
debug = !debug; debug = !debug;
break; break;
case INIT_CMD_RELOAD: case INIT_CMD_RELOAD: /* 'init q' and 'initctl reload' */
service_reload_dynamic(); service_reload_dynamic();
break; break;
@@ -264,7 +272,7 @@ static void cb(uev_t *w, void *UNUSED(arg), int UNUSED(events))
break; break;
case INIT_CMD_STOP_SVC: case INIT_CMD_STOP_SVC:
result = do_stop(rq.data, sizeof(rq.data)); result = do_pause(rq.data, sizeof(rq.data));
break; break;
case INIT_CMD_RELOAD_SVC: case INIT_CMD_RELOAD_SVC:
@@ -275,9 +283,11 @@ static void cb(uev_t *w, void *UNUSED(arg), int UNUSED(events))
result = do_restart(rq.data, sizeof(rq.data)); result = do_restart(rq.data, sizeof(rq.data));
break; break;
#ifndef INETD_DISABLED
case INIT_CMD_QUERY_INETD: case INIT_CMD_QUERY_INETD:
result = do_query_inetd(rq.data, sizeof(rq.data)); result = do_query_inetd(rq.data, sizeof(rq.data));
break; break;
#endif
case INIT_CMD_EMIT: case INIT_CMD_EMIT:
result = do_handle_emit(rq.data, sizeof(rq.data)); result = do_handle_emit(rq.data, sizeof(rq.data));
+10 -5
View File
@@ -116,18 +116,21 @@ int conf_parse_runlevels(char *runlevels)
void conf_parse_events(svc_t *svc, char *events) void conf_parse_events(svc_t *svc, char *events)
{ {
size_t i = 0; size_t i = 0;
char *ptr = events; char *ptr;
if (!events)
return;
if (!svc) { if (!svc) {
_e("Invalid service pointer"); _e("Invalid service pointer");
return; return;
} }
/* First character must be '!' if SIGHUP is not supported. */ /* By default we assume UNIX daemons support SIGHUP */
svc->sighup = 1; svc->sighup = 1;
if (!events)
return;
/* First character must be '!' if SIGHUP is not supported. */
ptr = events;
if (ptr[i] == '!') { if (ptr[i] == '!') {
svc->sighup = 0; svc->sighup = 0;
ptr++; ptr++;
@@ -415,6 +418,8 @@ void conf_reload_dynamic(void)
while (num--) while (num--)
free(e[num]); free(e[num]);
free(e); free(e);
set_hostname(&hostname);
} }
int conf_parse_config(void) int conf_parse_config(void)
Vendored
+9 -8
View File
@@ -22,6 +22,7 @@ defaults()
plugindir=${plugindir:="$libdir/$pdir"} plugindir=${plugindir:="$libdir/$pdir"}
# The initctl FIFO, should probably be in /run, not /dev # The initctl FIFO, should probably be in /run, not /dev
fifo=${fifo:="/dev/initctl"} fifo=${fifo:="/dev/initctl"}
random=${random:="/var/lib/urandom/random-seed"}
conf="finit.conf" conf="finit.conf"
config=${config:="$sysconfdir/$conf"} config=${config:="$sysconfdir/$conf"}
confdir=${confdir:="finit.d"} confdir=${confdir:="finit.d"}
@@ -149,9 +150,9 @@ usage()
echo " --with-fifo=FIFO FIFO for initctl plugin, default '$fifo'" echo " --with-fifo=FIFO FIFO for initctl plugin, default '$fifo'"
echo " --with-config=CONFIG Finit CONFIG file, default '\$sysconfdir/$conf'" echo " --with-config=CONFIG Finit CONFIG file, default '\$sysconfdir/$conf'"
echo " --with-heading=GREET Display GREET instead of Finit version at boot" echo " --with-heading=GREET Display GREET instead of Finit version at boot"
echo " --with-randomseed=SEED Seed /dev/urandom from file SEED. On Debian/Ubuntu" echo " --with-randomseed=SEED Seed /dev/urandom at boot from SEED. Usually found in"
echo " systems, set this to /var/lib/urandom/random-seed" echo " standard Linux systems at $random"
echo " Default: none" echo " which is also the default. Requires urandom plugin!"
echo " --with-plugins=\"a b c\" Build plugins 'a', 'b' and 'c', either as dynamic .so" echo " --with-plugins=\"a b c\" Build plugins 'a', 'b' and 'c', either as dynamic .so"
echo " files, or as built-in if --enable-static is given," echo " files, or as built-in if --enable-static is given,"
echo " defaults to all plugins. Exclude extension!" echo " defaults to all plugins. Exclude extension!"
@@ -345,9 +346,9 @@ fi
echo >> config.mk echo >> config.mk
if [ $debug -eq 1 ]; then if [ $debug -eq 1 ]; then
echo "CPPFLAGS += -O0 -g" >> config.mk echo "CFLAGS += -O0 -g" >> config.mk
else else
echo "CPPFLAGS += -Os" >> config.mk echo "CFLAGS += -O2" >> config.mk
fi fi
echo >> config.mk echo >> config.mk
@@ -375,7 +376,7 @@ fi
if [ x"$libite" != x"" ]; then if [ x"$libite" != x"" ]; then
echo "LIBITE = $libite" >> config.mk echo "LIBITE = $libite" >> config.mk
echo "CFLAGS += -I\$(LIBITE)/include" >> config.mk echo "CPPFLAGS += -I\$(LIBITE)/include" >> config.mk
echo "LDFLAGS += -L\$(LIBITE)/lib" >> config.mk echo "LDFLAGS += -L\$(LIBITE)/lib" >> config.mk
echo "LDLIBS += -l:libite.so.2" >> config.mk echo "LDLIBS += -l:libite.so.2" >> config.mk
else else
@@ -386,7 +387,7 @@ fi
if [ x"$libuev" != x"" ]; then if [ x"$libuev" != x"" ]; then
echo "LIBUEV = $libuev" >> config.mk echo "LIBUEV = $libuev" >> config.mk
echo "CFLAGS += -I\$(LIBUEV)/include" >> config.mk echo "CPPFLAGS += -I\$(LIBUEV)/include" >> config.mk
echo "LDFLAGS += -L\$(LIBUEV)/lib" >> config.mk echo "LDFLAGS += -L\$(LIBUEV)/lib" >> config.mk
echo "LDLIBS += -l:libuev.so.1" >> config.mk echo "LDLIBS += -l:libuev.so.1" >> config.mk
else else
@@ -397,7 +398,7 @@ fi
echo >> config.mk echo >> config.mk
echo "export libdir plugindir incdir" >> config.mk echo "export libdir plugindir incdir" >> config.mk
echo "export CPPFLAGS LDFLAGS LDLIBS STATIC" >> config.mk echo "export CFLAGS CPPFLAGS LDFLAGS LDLIBS STATIC" >> config.mk
############################################################################## ##############################################################################
echo "/* Generated by finit configure script. */" > config.h echo "/* Generated by finit configure script. */" > config.h
+16 -10
View File
@@ -140,9 +140,14 @@ int event_cache_if(char *ifname)
return entry->updown; return entry->updown;
} }
static int validate_events(char *events) static int has_events(char *events)
{ {
return !events || !events[0]; return events && events[0];
}
static int matches_event(char *events, char *event)
{
return strcasestr(events, event) ? 1 : 0;
} }
int event_service_cond(char *events) int event_service_cond(char *events)
@@ -152,7 +157,7 @@ int event_service_cond(char *events)
char temp[MAX_ARG_LEN]; char temp[MAX_ARG_LEN];
/* No required events, condition satisfied */ /* No required events, condition satisfied */
if (validate_events(events)) if (!has_events(events))
return cond; return cond;
strlcpy(temp, events, sizeof(temp)); strlcpy(temp, events, sizeof(temp));
@@ -201,14 +206,16 @@ void event_dispatch(char *msg)
/* Iterate over svc_t and call service_restart() for event matches */ /* Iterate over svc_t and call service_restart() for event matches */
for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) { for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) {
if (svc->type != SVC_TYPE_SERVICE || validate_events(svc->events)) if (svc->type != SVC_TYPE_SERVICE ||
!service_enabled(svc, 1, NULL) ||
!has_events(svc->events) ||
!matches_event(svc->events, msg)) {
_d("No match for %s in service %s", msg, svc->cmd);
continue; continue;
}
if (change == 1) { if (change == 1) {
if (!service_enabled(svc, 1, NULL)) _d("%s matches <%s> %s (re)starting ...", msg, svc->events, svc->cmd);
continue;
_d("Got event %s, (re)starting %s ...", svc->events, svc->cmd);
if (!svc->pid) { if (!svc->pid) {
service_start(svc); service_start(svc);
continue; continue;
@@ -220,12 +227,11 @@ void event_dispatch(char *msg)
service_restart(svc); service_restart(svc);
} else { /* change == -1 */ } else { /* change == -1 */
if (svc->pid && !event_service_cond(svc->events)) if (svc->pid && !event_service_cond(svc->events))
service_stop(svc); service_stop(svc, SVC_CONDHALT_STATE);
} }
} }
} }
/** /**
* Local Variables: * Local Variables:
* version-control: t * version-control: t
+12 -1
View File
@@ -71,6 +71,7 @@ static int banner(void)
int main(int argc, char* argv[]) int main(int argc, char* argv[])
{ {
int err;
uev_ctx_t loop; uev_ctx_t loop;
/* /*
@@ -118,6 +119,10 @@ int main(int argc, char* argv[])
/* /*
* Populate /dev and prepare for runtime events from kernel. * Populate /dev and prepare for runtime events from kernel.
*/ */
#ifdef EMBEDDED_SYSTEM
if (debug)
touch("/dev/mdev.log");
#endif
run_interactive(SETUP_DEVFS, "Populating device tree"); run_interactive(SETUP_DEVFS, "Populating device tree");
/* /*
@@ -151,7 +156,13 @@ int main(int argc, char* argv[])
plugin_run_hooks(HOOK_ROOTFS_UP); plugin_run_hooks(HOOK_ROOTFS_UP);
umask(0); umask(0);
run("/bin/mount -na"); print_desc("Mounting filesystems", NULL);
err = run("/bin/mount -na");
print_result(err);
if (err)
plugin_run_hooks(HOOK_MOUNT_ERROR);
run("/sbin/swapon -ea"); run("/sbin/swapon -ea");
umask(0022); umask(0022);
+20 -4
View File
@@ -84,17 +84,27 @@ int runlevel_get(void)
*/ */
char *runlevel_string(int levels) char *runlevel_string(int levels)
{ {
int i, pos = 1;; int i, pos = 1;
static char lvl[10] = "[]"; static char lvl[20];
memset(lvl, 0, sizeof(lvl));
lvl[0] = '[';
for (i = 0; i < 10; i++) { for (i = 0; i < 10; i++) {
if (ISSET(levels, i)) { if (ISSET(levels, i)) {
if (runlevel == i)
pos = strlcat(lvl, "\e[1m", sizeof(lvl));
if (i == 0) if (i == 0)
lvl[pos++] = 'S'; lvl[pos++] = 'S';
else else
lvl[pos++] = '0' + i; lvl[pos++] = '0' + i;
if (runlevel == i)
pos = strlcat(lvl, "\e[0m", sizeof(lvl));
} }
} }
lvl[pos++] = ']'; lvl[pos++] = ']';
lvl[pos] = 0; lvl[pos] = 0;
@@ -174,27 +184,33 @@ int print_result(int fail)
return fail; return fail;
} }
#ifndef ENABLE_STATIC
int getuser(char *username) int getuser(char *username)
{ {
#ifdef ENABLE_STATIC
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; 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 #endif
}
/* Signal safe sleep ... we get a lot of SIGCHLD at reboot */ /* Signal safe sleep ... we get a lot of SIGCHLD at reboot */
void do_sleep(unsigned int sec) void do_sleep(unsigned int sec)
+29 -2
View File
@@ -212,12 +212,27 @@ void inetd_stop(inetd_t *inetd)
/* Stop any running service, not allowed anymore. */ /* Stop any running service, not allowed anymore. */
if (svc->pid) if (svc->pid)
service_stop(svc); service_stop(svc, SVC_WAITING_STATE);
} }
static int getent(char *service, char *proto, struct servent **sv, struct protoent **pv) static int getent(char *service, char *proto, struct servent **sv, struct protoent **pv)
{ {
#ifdef ENABLE_STATIC
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;
*sv = &lfs;
}
#else
*sv = getservbyname(service, proto); *sv = getservbyname(service, proto);
#endif
if (!*sv) { if (!*sv) {
const char *errstr; const char *errstr;
static struct servent s; static struct servent s;
@@ -238,8 +253,20 @@ static int getent(char *service, char *proto, struct servent **sv, struct protoe
*sv = &s; *sv = &s;
} }
if (pv) { if (pv && (*sv)->s_proto) {
#ifdef ENABLE_STATIC
int proto_num;
static struct protoent lfp;
proto_num = fgetint("/etc/protocols", " \n\t", (*sv)->s_proto);
if (proto_num > 0) {
lfp.p_name = proto;
lfp.p_proto = proto_num;
}
*pv = &lfp;
#else
*pv = getprotobyname((*sv)->s_proto); *pv = getprotobyname((*sv)->s_proto);
#endif
if (!*pv) { if (!*pv) {
_e("Cannot find proto %s, skipping.", (*sv)->s_proto); _e("Cannot find proto %s, skipping.", (*sv)->s_proto);
return errno = EINVAL; return errno = EINVAL;
+23 -14
View File
@@ -149,26 +149,26 @@ static int show_status(char *UNUSED(arg))
} }
for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) { for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) {
int inetd = svc_is_inetd(svc); char jobid[10], args[512] = "";
char jobid[10], args[80] = "";
struct init_request rq = {
.magic = INIT_MAGIC,
.cmd = INIT_CMD_QUERY_INETD,
};
if (svc_is_unique(svc)) if (svc_is_unique(svc))
snprintf(jobid, sizeof(jobid), "%d", svc->job); snprintf(jobid, sizeof(jobid), "%d", svc->job);
else else
snprintf(jobid, sizeof(jobid), "%d:%d", svc->job, svc->id); snprintf(jobid, sizeof(jobid), "%d:%d", svc->job, svc->id);
printf("%-5s %7s %-6d %-9s ", jobid, svc_status(svc), svc->pid, runlevel_string(svc->runlevels)); printf("%-5s %7s %-6d %-18.18s ", jobid, svc_status(svc), svc->pid, runlevel_string(svc->runlevels));
if (!verbose) { if (!verbose) {
printf("%-20s %s\n", svc->cmd, svc->desc); printf("%-20s %s\n", svc->cmd, svc->desc);
continue; continue;
} }
if (inetd) { #ifndef INETD_DISABLED
if (svc_is_inetd(svc)) {
char *info; char *info;
struct init_request rq = {
.magic = INIT_MAGIC,
.cmd = INIT_CMD_QUERY_INETD,
};
snprintf(rq.data, sizeof(rq.data), "%s", jobid); snprintf(rq.data, sizeof(rq.data), "%s", jobid);
if (do_send(&rq, sizeof(rq))) { if (do_send(&rq, sizeof(rq))) {
@@ -184,7 +184,10 @@ static int show_status(char *UNUSED(arg))
} }
printf("%s %s\n", svc->cmd, info); printf("%s %s\n", svc->cmd, info);
} else { }
else
#endif /* !INETD_DISABLED */
{
int i; int i;
for (i = 1; i < MAX_NUM_SVC_ARGS; i++) { for (i = 1; i < MAX_NUM_SVC_ARGS; i++) {
@@ -203,19 +206,20 @@ static int usage(int rc)
{ {
fprintf(stderr, "Usage: %s [OPTIONS] <COMMAND>\n\n" fprintf(stderr, "Usage: %s [OPTIONS] <COMMAND>\n\n"
"Options:\n" "Options:\n"
" -d, --debug Debug initctl (client)\n"
" -v, --verbose Verbose output\n" " -v, --verbose Verbose output\n"
" -h, --help This help text\n\n" " -h, --help This help text\n\n"
"Commands:\n" "Commands:\n"
" debug Toggle Finit debug\n" " debug Toggle Finit (daemon) debug\n"
" emit <EV> Emit an event. Can be a predefined event: RELOAD, STOP,\n" " emit <EV> Emit an event. Can be a predefined event: RELOAD, STOP,\n"
" START, or a custom string to match the event list in a\n" " START, or a custom string to match the event list in a\n"
" service stanza, e.g: GW, IFUP:IFNAME, IFDN:IFNAME, where\n" " service stanza, e.g: GW:UP, IFUP:IFNAME, IFDN:IFNAME,\n"
" IFNAME is the interface name, e.g. eth0\n" " where IFNAME is the interface name, e.g. eth0\n"
" reload Reload *.conf in /etc/finit.d/ and activate changes\n" " reload Reload *.conf in /etc/finit.d/ and activate changes\n"
" runlevel [0-9] Show or set runlevel: 0 halt, 6 reboot\n" " runlevel [0-9] Show or set runlevel: 0 halt, 6 reboot\n"
" status | show Show status of services\n" " status | show Show status of services\n"
" start <JOB|NAME> Start stopped job or service\n" " start <JOB|NAME> Start stopped job or service\n"
" stop <JOB|NAME> Stop running job or service\n" " stop <JOB|NAME> Stop/Pause running job or service\n"
" restart <JOB|NAME> Restart (stop/start) job or service\n" " restart <JOB|NAME> Restart (stop/start) job or service\n"
" reload <JOB|NAME> Reload (SIGHUP) job or service\n" " reload <JOB|NAME> Reload (SIGHUP) job or service\n"
" version Show Finit version\n\n", __progname); " version Show Finit version\n\n", __progname);
@@ -241,17 +245,22 @@ int main(int argc, char *argv[])
}; };
struct option long_options[] = { struct option long_options[] = {
{"help", 0, NULL, 'h'}, {"help", 0, NULL, 'h'},
{"debug", 0, NULL, 'd'},
{"verbose", 0, NULL, 'v'}, {"verbose", 0, NULL, 'v'},
{NULL, 0, NULL, 0} {NULL, 0, NULL, 0}
}; };
verbose = 0; verbose = 0;
while ((c = getopt_long(argc, argv, "h?v", long_options, NULL)) != EOF) { while ((c = getopt_long(argc, argv, "dh?v", long_options, NULL)) != EOF) {
switch(c) { switch(c) {
case 'h': case 'h':
case '?': case '?':
return usage(0); return usage(0);
case 'd':
debug = 1;
break;
case 'v': case 'v':
verbose = 1; verbose = 1;
break; break;
+1 -1
Submodule libite updated: 4d6c32f81a...12ed342d55
+1 -1
Submodule libuev updated: a8d8705c34...cf5e729dd3
+5
View File
@@ -317,11 +317,16 @@ int plugin_load_all(uev_ctx_t *ctx, char *path)
closedir(dp); closedir(dp);
#else #else
_d("Finit built statically, not loading plugins from %s ...", path); _d("Finit built statically, not loading plugins from %s ...", path);
if (verbose)
print_desc("Initializing plugins", NULL);
#endif /* ENABLE_STATIC */ #endif /* ENABLE_STATIC */
/* Always initialize plugins */ /* Always initialize plugins */
init_plugins(ctx); init_plugins(ctx);
#ifndef ENABLE_STATIC
exit: exit:
#endif
if (verbose) if (verbose)
print_result(fail); print_result(fail);
+1
View File
@@ -43,6 +43,7 @@
typedef enum { typedef enum {
/* Bootstrap hooks */ /* Bootstrap hooks */
HOOK_ROOTFS_UP = 0, HOOK_ROOTFS_UP = 0,
HOOK_MOUNT_ERROR,
HOOK_BASEFS_UP, HOOK_BASEFS_UP,
HOOK_NETWORK_UP, HOOK_NETWORK_UP,
HOOK_SVC_UP, HOOK_SVC_UP,
+12
View File
@@ -14,7 +14,12 @@ endif
include ../common.mk include ../common.mk
ifneq ($(STATIC), 1)
all: $(PLUGINS) all: $(PLUGINS)
else
all:
@true
endif
clean: clean:
-@$(RM) $(PLUGINS) -@$(RM) $(PLUGINS)
@@ -22,6 +27,7 @@ clean:
distclean: distclean:
-@$(RM) *.o *.so $(JUNK) $(DEPS) -@$(RM) *.o *.so $(JUNK) $(DEPS)
ifneq ($(STATIC), 1)
install: all install: all
@install -d $(DESTDIR)$(plugindir) @install -d $(DESTDIR)$(plugindir)
@for plugin in $(PLUGINS); do \ @for plugin in $(PLUGINS); do \
@@ -35,6 +41,12 @@ uninstall:
rm $(DESTDIR)$(plugindir)/$$plugin 2>/dev/null; \ rm $(DESTDIR)$(plugindir)/$$plugin 2>/dev/null; \
done done
-@rmdir $(DESTDIR)$(plugindir) 2>/dev/null -@rmdir $(DESTDIR)$(plugindir) 2>/dev/null
else
install:
@true
uninstall:
@true
endif
ifneq ($(MAKECMDGOALS),distclean) ifneq ($(MAKECMDGOALS),distclean)
-include $(DEPS) -include $(DEPS)
+1
View File
@@ -39,6 +39,7 @@ static void restore(void *UNUSED(arg))
} }
static plugin_t plugin = { static plugin_t plugin = {
.name = __FILE__,
.hook[HOOK_BASEFS_UP] = { .hook[HOOK_BASEFS_UP] = {
.cb = restore .cb = restore
}, },
+3 -5
View File
@@ -24,15 +24,12 @@
#include <string.h> #include <string.h>
#include <utmp.h> #include <utmp.h>
#include "../config.h"
#include "../finit.h" #include "../finit.h"
#include "../helpers.h" #include "../helpers.h"
#include "../plugin.h" #include "../plugin.h"
#include "libite/lite.h" #include "libite/lite.h"
#ifdef ENABLE_STATIC
#error This plugin uses getuser(), which relies on dynamically linked GLIBC. Cannot be built statically!
#endif
/* /*
* Setup standard FHS 2.3 structure in /var, and * Setup standard FHS 2.3 structure in /var, and
* write runlevel to UTMP, needed by, e.g., printerdrake. * write runlevel to UTMP, needed by, e.g., printerdrake.
@@ -49,6 +46,7 @@ static void setup(void *UNUSED(arg))
makedir("/var/lib", 0755); makedir("/var/lib", 0755);
makedir("/var/lib/misc", 0755); makedir("/var/lib/misc", 0755);
makedir("/var/lib/alarm", 0755); makedir("/var/lib/alarm", 0755);
makedir("/var/lib/urandom",0755);
makedir("/var/lock", 0755); makedir("/var/lock", 0755);
makedir("/var/log", 0755); makedir("/var/log", 0755);
makedir("/var/mail", 0755); makedir("/var/mail", 0755);
@@ -89,7 +87,7 @@ static void setup(void *UNUSED(arg))
} }
static plugin_t plugin = { static plugin_t plugin = {
.name = "bootmisc", .name = __FILE__,
.hook[HOOK_BASEFS_UP] = { .hook[HOOK_BASEFS_UP] = {
.cb = setup .cb = setup
}, },
+1
View File
@@ -42,6 +42,7 @@ static void setup(void *UNUSED(arg))
} }
static plugin_t plugin = { static plugin_t plugin = {
.name = __FILE__,
.hook[HOOK_NETWORK_UP] = { .hook[HOOK_NETWORK_UP] = {
.cb = setup .cb = setup
}, },
+1
View File
@@ -41,6 +41,7 @@ static void restore(void *UNUSED(arg))
} }
static plugin_t plugin = { static plugin_t plugin = {
.name = __FILE__,
.hook[HOOK_BASEFS_UP] = { .hook[HOOK_BASEFS_UP] = {
.cb = restore .cb = restore
}, },
+1
View File
@@ -42,6 +42,7 @@
static void parse(void *arg, int fd, int events); static void parse(void *arg, int fd, int events);
static plugin_t plugin = { static plugin_t plugin = {
.name = __FILE__,
.io = { .io = {
.cb = parse, .cb = parse,
.flags = PLUGIN_IO_READ, .flags = PLUGIN_IO_READ,
+25 -25
View File
@@ -29,16 +29,20 @@
#include "../helpers.h" #include "../helpers.h"
#include "../plugin.h" #include "../plugin.h"
static int nlmsg_validate(struct nlmsghdr *nlmsg, size_t len) static int nlmsg_validate(struct nlmsghdr *nh, size_t len)
{ {
if (!NLMSG_OK(nlmsg, len)) if (!NLMSG_OK(nh, len))
return 1; return 1;
if (len < sizeof(struct nlmsghdr)) if (nh->nlmsg_type == NLMSG_DONE) {
_d("Done with netlink messages.");
return 1; return 1;
}
if (len < nlmsg->nlmsg_len) if (nh->nlmsg_type == NLMSG_ERROR) {
_d("Netlink reports error.");
return 1; return 1;
}
return 0; return 0;
} }
@@ -155,32 +159,28 @@ static void nl_link(struct nlmsghdr *nlmsg)
static void nl_callback(void *UNUSED(arg), int sd, int UNUSED(events)) static void nl_callback(void *UNUSED(arg), int sd, int UNUSED(events))
{ {
ssize_t len; ssize_t len;
static char replybuf[2048]; static char buf[4096];
struct nlmsghdr *p = (struct nlmsghdr *)replybuf; struct nlmsghdr *nh;
memset(replybuf, 0, sizeof(replybuf)); memset(buf, 0, sizeof(buf));
len = recv(sd, replybuf, sizeof(replybuf), 0); len = recv(sd, buf, sizeof(buf), 0);
if (len < 0) { if (len < 0) {
if (errno != EINTR) /* Signal */ if (errno != EINTR) /* Signal */
_pe("recv()"); _pe("recv()");
return; return;
} }
for (; len > 0; p = NLMSG_NEXT(p, len)) { for (nh = (struct nlmsghdr *)buf; !nlmsg_validate(nh, len); nh = NLMSG_NEXT(nh, len)) {
if (nlmsg_validate(p, len)) { //_d("Well formed netlink message received. type %d ...", nh->nlmsg_type);
_e("Packet too small or truncated!"); if (nh->nlmsg_type == RTM_NEWROUTE || nh->nlmsg_type == RTM_DELROUTE)
return; nl_route(nh);
}
_d("Well formed netlink message received.");
if (p->nlmsg_type == RTM_NEWROUTE || p->nlmsg_type == RTM_DELROUTE)
nl_route(p);
else else
nl_link(p); nl_link(nh);
} }
} }
static plugin_t plugin = { static plugin_t plugin = {
.name = __FILE__,
.io = { .io = {
.cb = nl_callback, .cb = nl_callback,
.flags = PLUGIN_IO_READ, .flags = PLUGIN_IO_READ,
@@ -190,20 +190,20 @@ static plugin_t plugin = {
PLUGIN_INIT(plugin_init) PLUGIN_INIT(plugin_init)
{ {
int sd; int sd;
struct sockaddr_nl addr; struct sockaddr_nl sa;
sd = socket(PF_NETLINK, SOCK_DGRAM | SOCK_NONBLOCK | SOCK_CLOEXEC, NETLINK_ROUTE); sd = socket(AF_NETLINK, SOCK_RAW | SOCK_NONBLOCK | SOCK_CLOEXEC, NETLINK_ROUTE);
if (sd < 0) { if (sd < 0) {
_pe("socket()"); _pe("socket()");
return; return;
} }
memset(&addr, 0, sizeof(addr)); memset(&sa, 0, sizeof(sa));
addr.nl_family = AF_NETLINK; sa.nl_family = AF_NETLINK;
addr.nl_groups = RTMGRP_IPV4_ROUTE | RTMGRP_LINK; sa.nl_groups = RTMGRP_IPV4_ROUTE | RTMGRP_LINK; // | RTMGRP_NOTIFY | RTMGRP_IPV4_IFADDR;
addr.nl_pid = getpid(); sa.nl_pid = getpid();
if (bind(sd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { if (bind(sd, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
_pe("bind()"); _pe("bind()");
close(sd); close(sd);
return; return;
+1
View File
@@ -66,6 +66,7 @@ static void setup(void *UNUSED(arg))
} }
static plugin_t plugin = { static plugin_t plugin = {
.name = __FILE__,
.hook[HOOK_BASEFS_UP] = { .hook[HOOK_BASEFS_UP] = {
.cb = setup .cb = setup
}, },
+1 -1
View File
@@ -62,7 +62,7 @@ static int rfc868(int type)
} }
static plugin_t plugin = { static plugin_t plugin = {
.name = "time", .name = "time", /* Must match the inetd /etc/services entry */
.inetd = { .inetd = {
.cmd = rfc868 .cmd = rfc868
} }
+9 -2
View File
@@ -37,6 +37,7 @@
static void watcher(void *arg, int fd, int events); static void watcher(void *arg, int fd, int events);
static plugin_t plugin = { static plugin_t plugin = {
.name = __FILE__,
.io = { .io = {
.cb = watcher, .cb = watcher,
.flags = PLUGIN_IO_READ, .flags = PLUGIN_IO_READ,
@@ -45,7 +46,10 @@ static plugin_t plugin = {
static void setup(void) static void setup(void)
{ {
plugin.io.fd = inotify_init1(IN_NONBLOCK); 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) if (-1 == plugin.io.fd || inotify_add_watch(plugin.io.fd, "/dev", IN_CREATE | IN_DELETE) < 0)
_e("Failed starting TTY watcher: %s", strerror(errno)); _e("Failed starting TTY watcher: %s", strerror(errno));
} }
@@ -59,9 +63,12 @@ static void watcher(void *UNUSED(arg), int fd, int UNUSED(events))
while ((len = read(fd, buf, sizeof(buf)))) { while ((len = read(fd, buf, sizeof(buf)))) {
if (-1 == len) { if (-1 == len) {
if (errno == EINVAL)
setup();
if (errno == EINTR) if (errno == EINTR)
continue; continue;
break;
break; /* Likely EAGAIN */
} }
snprintf(name, sizeof(name), "/dev/%s", notified->name); snprintf(name, sizeof(name), "/dev/%s", notified->name);
+42 -8
View File
@@ -22,29 +22,63 @@
*/ */
#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 "../config.h"
#include "../finit.h" #include "../finit.h"
#include "libite/lite.h"
#include "../helpers.h" #include "../helpers.h"
#include "../plugin.h" #include "../plugin.h"
#include "libite/lite.h"
static void setup(void *UNUSED(arg)) static void setup(void *UNUSED(arg))
{ {
#ifdef RANDOMSEED #ifdef RANDOMSEED
copyfile(RANDOMSEED, "/dev/urandom", 0, 0); if (!fexist(RANDOMSEED)) {
unlink(RANDOMSEED); int ret = 1;
FILE *fp;
print_desc("Bootstrapping random seed", NULL);
umask(077); umask(077);
copyfile("/dev/urandom", RANDOMSEED, 4096, 0); 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);
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", } .depends = { "bootmisc", }
}; };
+1
View File
@@ -54,6 +54,7 @@ static void setup(void *UNUSED(arg))
} }
static plugin_t plugin = { static plugin_t plugin = {
.name = __FILE__,
.hook[HOOK_NETWORK_UP] = { .hook[HOOK_NETWORK_UP] = {
.cb = setup .cb = setup
}, },
+106 -35
View File
@@ -41,11 +41,14 @@
#define RESPAWN_MAX 10 /* Prevent endless respawn of faulty services. */ #define RESPAWN_MAX 10 /* Prevent endless respawn of faulty services. */
static int dyn_stop_cnt = 0;
static int is_norespawn (void); static int is_norespawn (void);
static void restart_lost_procs (void); static void restart_lost_procs (void);
static void svc_dance (svc_t *svc); static void svc_dance (svc_t *svc);
#ifndef INETD_DISABLED
static svc_t *find_inetd_svc (char *path, char *service, char *proto); static svc_t *find_inetd_svc (char *path, char *service, char *proto);
#endif
/** /**
* service_bootstrap - Start bootstrap services and tasks * service_bootstrap - Start bootstrap services and tasks
@@ -87,6 +90,8 @@ void service_bootstrap(void)
*/ */
svc_cmd_t service_enabled(svc_t *svc, int event, void *arg) svc_cmd_t service_enabled(svc_t *svc, int event, void *arg)
{ {
svc_cmd_t cmd = SVC_START; /* Default to start, since listed in finit.conf */
if (!svc) { if (!svc) {
errno = EINVAL; errno = EINVAL;
return SVC_STOP; return SVC_STOP;
@@ -98,9 +103,15 @@ svc_cmd_t service_enabled(svc_t *svc, int event, void *arg)
/* /*
* Event conditions for services are ignored during bootstrap. * Event conditions for services are ignored during bootstrap.
*/ */
_d("Checking %s runlevel %d and events %s", svc->cmd, runlevel, svc->events);
if (runlevel && !event_service_cond(svc->events)) if (runlevel && !event_service_cond(svc->events))
return SVC_STOP; return SVC_STOP;
if (svc->state == SVC_RELOAD_STATE)
cmd = SVC_RELOAD;
if (svc->state == SVC_PAUSED_STATE)
cmd = SVC_STOP;
/* Is there a service plugin registered? */ /* Is there a service plugin registered? */
if (svc->cb) { if (svc->cb) {
int status; int status;
@@ -113,10 +124,8 @@ svc_cmd_t service_enabled(svc_t *svc, int event, void *arg)
return SVC_STOP; return SVC_STOP;
} }
if (!pid) { if (!pid)
status = svc->cb(svc, event, arg); _exit(svc->cb(svc, event, arg));
exit(status);
}
if (waitpid(pid, &status, 0) == -1) { if (waitpid(pid, &status, 0) == -1) {
_pe("Failed reading status from %s callback", svc->cmd); _pe("Failed reading status from %s callback", svc->cmd);
@@ -124,11 +133,13 @@ svc_cmd_t service_enabled(svc_t *svc, int event, void *arg)
} }
/* Callback normally exits here. */ /* Callback normally exits here. */
if (WIFEXITED(status)) if (WIFEXITED(status)) {
return WEXITSTATUS(status); svc_cmd_t tmp = WEXITSTATUS(status);
return tmp == SVC_START ? cmd : tmp;
}
/* Check for SEGFAULT or other error ... */ /* Check for SEGFAULT or other error ... */
if (WCOREDUMP(status)) if (WIFSIGNALED(status) && WCOREDUMP(status))
_e("Callback to %s crashed!\n", svc->cmd); _e("Callback to %s crashed!\n", svc->cmd);
else else
_e("Callback to %s did not exit normally!\n", svc->cmd); _e("Callback to %s did not exit normally!\n", svc->cmd);
@@ -136,8 +147,13 @@ svc_cmd_t service_enabled(svc_t *svc, int event, void *arg)
return SVC_STOP; return SVC_STOP;
} }
/* No service plugin, default to start, since listed in finit.conf */ _d("%s => %s", svc->cmd, (cmd == SVC_START
return SVC_START; ? "SVC_START"
: (cmd == SVC_RELOAD
? "SVC_RELOAD"
: "SVC_STOP")));
return cmd;
} }
/* Remember: service_enabled() must be called before calling service_start() */ /* Remember: service_enabled() must be called before calling service_start() */
@@ -278,6 +294,8 @@ int service_start(svc_t *svc)
_e("%starting %s: %s", respawn ? "Res" : "S", svc->cmd, buf); _e("%starting %s: %s", respawn ? "Res" : "S", svc->cmd, buf);
} }
sig_unblock();
if (svc->inetd.cmd) if (svc->inetd.cmd)
status = svc->inetd.cmd(svc->inetd.type); status = svc->inetd.cmd(svc->inetd.type);
else else
@@ -294,6 +312,7 @@ int service_start(svc_t *svc)
exit(status); exit(status);
} }
svc->pid = pid; svc->pid = pid;
svc->state = SVC_RUNNING_STATE;
if (svc_is_inetd(svc)) { if (svc_is_inetd(svc)) {
if (svc->inetd.type == SOCK_STREAM) if (svc->inetd.type == SOCK_STREAM)
@@ -315,9 +334,9 @@ int service_start(svc_t *svc)
return 0; return 0;
} }
int service_stop(svc_t *svc) int service_stop(svc_t *svc, int state)
{ {
int res = 1; int res = 0;
if (!svc) if (!svc)
return 1; return 1;
@@ -331,6 +350,12 @@ int service_stop(svc_t *svc)
if (SVC_TYPE_SERVICE != svc->type) if (SVC_TYPE_SERVICE != svc->type)
return 0; return 0;
_d("Service %s state %d, new state %d, sighup %d", svc->cmd, svc->state, state, svc->sighup);
if (state == SVC_RELOAD_STATE && svc->sighup)
goto exit;
if (state == SVC_RESTART_STATE && svc->sighup)
return service_reload(svc);
if (runlevel != 1 && verbose) if (runlevel != 1 && verbose)
print_desc("Stopping ", svc->desc); print_desc("Stopping ", svc->desc);
@@ -340,7 +365,8 @@ int service_stop(svc_t *svc)
if (runlevel != 1 && verbose) if (runlevel != 1 && verbose)
print_result(res); print_result(res);
exit: exit:
svc->pid = 0; if (!res)
svc->state = state;
svc->restart_counter = 0; svc->restart_counter = 0;
return res; return res;
@@ -363,8 +389,36 @@ void service_start_dynamic(void)
svc_clean_dynamic(service_unregister); svc_clean_dynamic(service_unregister);
} }
/*
* Unless there are services we must collect first (wait for
* them to stop), we can call HOOK_SVC_RECONF here.
*/
static int service_stop_done(svc_t *svc)
{
if (svc && !svc_is_changed(svc))
return 0;
if (svc && dyn_stop_cnt)
dyn_stop_cnt--;
if (!dyn_stop_cnt) {
_d("All disabled/removed services have been stoppped, calling reconf hooks ...");
plugin_run_hooks(HOOK_SVC_RECONF); /* Reconfigure HW/VLANs/etc here */
/* Finish off by starting/reload modified/new services */
if (svc->state == SVC_RELOAD_STATE)
service_start_dynamic();
}
return 1;
}
/** /**
* service_stop_dynamic - Stop disabled/removed dynamic services * service_stop_dynamic - Stop disabled/removed dynamic services
*
* We call it "stop", but in reality it could be "skip" as well, if the
* service supports SIGHUP. This function is just one step on the road
* to reload all modified services.
*/ */
void service_stop_dynamic(void) void service_stop_dynamic(void)
{ {
@@ -372,31 +426,41 @@ void service_stop_dynamic(void)
_d("Stopping disabled/removed services ..."); _d("Stopping disabled/removed services ...");
for (svc = svc_dynamic_iterator(1); svc; svc = svc_dynamic_iterator(0)) { for (svc = svc_dynamic_iterator(1); svc; svc = svc_dynamic_iterator(0)) {
if (svc_is_changed(svc)) if (svc_is_changed(svc)) {
service_stop(svc); dyn_stop_cnt++;
_d("Marking service %s as state %d", svc->cmd, SVC_RELOAD_STATE);
service_stop(svc, SVC_RELOAD_STATE);
}
} }
_d("All disabled/removed services have been stoppped, calling reconf hooks ..."); /* Check if we need to collect any services before calling user HOOK */
plugin_run_hooks(HOOK_SVC_RECONF); /* Reconfigure HW/VLANs/etc here */ service_stop_done(NULL);
} }
/* stop + start /**
* service_restart - Restart or SIGHUP a process
* *
* XXX: This should be refactored into a background job AND marked such * Unfortunately we cannot call service_start() here because we must
* so that the service monitor doesn't attempt to restart it! * wait for the svc to actually be collected by the service_monitor()
* first. Currently this means that an initctl user will not get
* correct feedback when restarting a service. (Prompt may return
* before we've actually started upp the service again.)
*
* XXX: This should be refactored to let initctl check the sighup
* flag and then to stop+start or reload.
*/ */
int service_restart(svc_t *svc) int service_restart(svc_t *svc)
{ {
int result = 0;
if (!svc) if (!svc)
return 1; return 1;
result += service_stop(svc); /* Ignore if finit is SIGSTOP'ed */
sleep(1); if (is_norespawn())
result += service_start(svc); return 0;
return result; svc->restart_counter = 0;
return service_stop(svc, SVC_RESTART_STATE);
} }
/** /**
@@ -415,16 +479,15 @@ int service_reload(svc_t *svc)
if (is_norespawn()) if (is_norespawn())
return 0; return 0;
if (!svc) { if (!svc)
_e("Failed, no svc pointer.");
return 1; return 1;
}
if (svc->pid <= 1) { if (svc->pid <= 1) {
_d("Bad PID %d for %s, SIGHUP", svc->pid, svc->cmd); _d("Bad PID %d for %s, SIGHUP", svc->pid, svc->cmd);
svc->pid = 0; svc->pid = 0;
return 1; return 1;
} }
svc->state = SVC_RUNNING_STATE;
_d("Sending SIGHUP to PID %d", svc->pid); _d("Sending SIGHUP to PID %d", svc->pid);
return kill(svc->pid, SIGHUP); return kill(svc->pid, SIGHUP);
@@ -445,8 +508,12 @@ void service_reload_dynamic(void)
/* Then stop any disabled/removed services and non-reloadable */ /* Then stop any disabled/removed services and non-reloadable */
service_stop_dynamic(); service_stop_dynamic();
/* Finish off by starting/reload modified/new services */ /*
service_start_dynamic(); * Finish off by starting/reloading modified/new services.
* Postponed to service_stop_done() to make sure all services
* are guaranteed to have been stopped before being started
* again.
*/
} }
/** /**
@@ -483,12 +550,12 @@ void service_runlevel(int newlevel)
inetd_stop(&svc->inetd); inetd_stop(&svc->inetd);
else else
#endif #endif
service_stop(svc); service_stop(svc, SVC_HALTED_STATE);
} }
/* ... or disabled/removed services from /etc/finit.d/ */ /* ... or disabled/removed services from /etc/finit.d/ */
if (svc_is_dynamic(svc) && svc_is_changed(svc)) if (svc_is_dynamic(svc) && svc_is_changed(svc))
service_stop(svc); service_stop(svc, SVC_HALTED_STATE);
} }
/* Prev runlevel services stopped, call hooks before starting new runlevel ... */ /* Prev runlevel services stopped, call hooks before starting new runlevel ... */
@@ -762,7 +829,7 @@ int service_register(int type, char *line, time_t mtime, char *username)
void service_unregister(svc_t *svc) void service_unregister(svc_t *svc)
{ {
service_stop(svc); service_stop(svc, SVC_HALTED_STATE);
svc_del(svc); svc_del(svc);
} }
@@ -808,6 +875,10 @@ void service_monitor(pid_t lost)
/* No longer running, update books. */ /* No longer running, update books. */
svc->pid = 0; svc->pid = 0;
/* Check if we're still collecting stopped dynamic services */
if (service_stop_done(svc))
break;
if (sig_stopped()) { if (sig_stopped()) {
_e("Stopped, not respawning killed processes."); _e("Stopped, not respawning killed processes.");
break; break;
@@ -861,7 +932,7 @@ static void svc_dance(svc_t *svc)
if (svc->pid) { if (svc->pid) {
if (SVC_STOP == cmd) if (SVC_STOP == cmd)
service_stop(svc); service_stop(svc, SVC_HALTED_STATE);
else if (SVC_RELOAD == cmd) else if (SVC_RELOAD == cmd)
service_reload(svc); service_reload(svc);
} else { } else {
+1 -1
View File
@@ -33,7 +33,7 @@ void service_unregister (svc_t *svc);
svc_cmd_t service_enabled (svc_t *svc, int event, void *arg); svc_cmd_t service_enabled (svc_t *svc, int event, void *arg);
int service_start (svc_t *svc); int service_start (svc_t *svc);
int service_stop (svc_t *svc); int service_stop (svc_t *svc, int state);
void service_start_dynamic (void); void service_start_dynamic (void);
void service_stop_dynamic (void); void service_stop_dynamic (void);
int service_restart (svc_t *svc); int service_restart (svc_t *svc);
+2
View File
@@ -96,6 +96,7 @@ void do_shutdown(int sig)
*/ */
static void sighup_cb(uev_t *UNUSED(w), void *UNUSED(arg), int UNUSED(events)) static void sighup_cb(uev_t *UNUSED(w), void *UNUSED(arg), int UNUSED(events))
{ {
/* INIT_CMD_RELOAD: 'init q', 'initctl reload', and SIGHUP */
service_reload_dynamic(); service_reload_dynamic();
} }
@@ -188,6 +189,7 @@ void sig_unblock(void)
struct sigaction sa; struct sigaction sa;
sigemptyset(&nmask); sigemptyset(&nmask);
sigaddset(&nmask, SIGHUP);
sigaddset(&nmask, SIGCHLD); sigaddset(&nmask, SIGCHLD);
sigaddset(&nmask, SIGINT); sigaddset(&nmask, SIGINT);
sigaddset(&nmask, SIGPWR); sigaddset(&nmask, SIGPWR);
+12 -1
View File
@@ -46,13 +46,23 @@ typedef enum {
SVC_TYPE_INETD /* Classic inetd service */ SVC_TYPE_INETD /* Classic inetd service */
} svc_type_t; } svc_type_t;
typedef enum {
SVC_HALTED_STATE = 0, /* Not allowed in runlevel, or not enabled. */
SVC_WAITING_STATE, /* Waiting for connection (inetd service) */
SVC_PAUSED_STATE, /* Stopped/Paused by user started on reload */
SVC_CONDHALT_STATE, /* Not allowed to run atm. event/state lost */
SVC_RESTART_STATE, /* Restarting service waiting to be stopped */
SVC_RELOAD_STATE, /* Reloading services, after .conf changed */
SVC_RUNNING_STATE, /* Currently running service, see svc->pid */
} svc_state_t;
#define FINIT_SHM_ID 0x494E4954 /* "INIT", see ascii(7) */ #define FINIT_SHM_ID 0x494E4954 /* "INIT", see ascii(7) */
#define MAX_ARG_LEN 64 #define MAX_ARG_LEN 64
#define MAX_STR_LEN 64 #define MAX_STR_LEN 64
#define MAX_USER_LEN 16 #define MAX_USER_LEN 16
#define MAX_NUM_FDS 64 /* Max number of I/O plugins */ #define MAX_NUM_FDS 64 /* Max number of I/O plugins */
#define MAX_NUM_SVC 64 /* Enough? */ #define MAX_NUM_SVC 64 /* Enough? */
#define MAX_NUM_SVC_ARGS 16 #define MAX_NUM_SVC_ARGS 32
/* Default enable for all services, can be stopped by means /* Default enable for all services, can be stopped by means
* of issuing an initctl call. E.g. * of issuing an initctl call. E.g.
@@ -63,6 +73,7 @@ typedef struct svc {
/* Service details */ /* Service details */
pid_t pid; pid_t pid;
svc_state_t state; /* Paused, Reloading, Restart, Running, ... */
svc_type_t type; svc_type_t type;
time_t mtime; /* Modification time for .conf from /etc/finit.d/ */ time_t mtime; /* Modification time for .conf from /etc/finit.d/ */
int dirty; /* Set if old mtime != new mtime => reloaded, int dirty; /* Set if old mtime != new mtime => reloaded,
+2 -1
View File
@@ -25,9 +25,10 @@
#ifndef FINIT_TTY_H_ #ifndef FINIT_TTY_H_
#define FINIT_TTY_H_ #define FINIT_TTY_H_
#include <limits.h>
#include "queue.h" /* BSD sys/queue.h API */ #include "queue.h" /* BSD sys/queue.h API */
#define EVENT_SIZE ((sizeof(struct inotify_event) + 20)) #define EVENT_SIZE ((sizeof(struct inotify_event) + NAME_MAX + 1))
typedef struct { typedef struct {
char *name; char *name;