Compare commits

..
43 Commits
Author SHA1 Message Date
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
32 changed files with 604 additions and 144 deletions
+88 -2
View File
@@ -1,7 +1,89 @@
Change Log
==========
All notable changes to the project are documented in this file.
All relevant changes are documented in this file.
[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][].
As of v2.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
--------------------
@@ -20,6 +102,7 @@ All notable changes to the project are documented in this file.
* 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
@@ -399,7 +482,10 @@ Major bug fix release.
* Initial release
[UNRELEASED]: https://github.com/troglobit/finit/compare/2.1...HEAD
[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 -1
View File
@@ -26,7 +26,7 @@
uninstall-exec uninstall-data uninstall-dev
#VERSION = $(shell git tag -l | tail -1)
VERSION = 2.1
VERSION = 2.4
NAME = finit
PKG = $(NAME)-$(VERSION)
DEV = $(NAME)-dev
+36 -22
View File
@@ -197,6 +197,11 @@ Syntax:
See `finit.h` for the `#define GETTY` that is called, along with the
default baud rate.
**Note:** BusyBox getty, used when Finit is built for embedded
systems, can take a `DEV` with *or* without `/dev/` prefix. Make
sure to call the configure script with `--enable-embedded` if this
is what you want.
* `console <DEV | /path/to/cmd [args]>`
Some embedded systems have a dedicated serial console/service port.
This command tells finit to not start getty directly, since there may
@@ -586,22 +591,25 @@ not return until the given command has fully completed.
Usage: initctl [OPTIONS] <COMMAND>
Options:
-v, --verbose Verbose output
-h, --help This help text
-d, --debug Debug initctl (client)
-v, --verbose Verbose output
-h, --help This help text
Commands:
debug Toggle init daemon debug
emit <EV> Emit an event: RELOAD, STOP, START, GW
IFUP:IFNAME, IFDN:IFNAME
IFNAME is the interface name, e.g. eth0
reload Reload *.conf in /etc/finit.d/, like SIGHUP
runlevel <0-9> Change runlevel: 0 (halt), 6 (reboot)
start <JOB#> Start a stopped service
stop <JOB#> Stop a running service
restart <JOB#> Restart (stop/start) a running service
reload <JOB#> Reload (SIGHUP) a running service
status | show List status of all services known to Finit
version Show Finit version
debug Toggle Finit (daemon) debug
help This help text
emit <EV> Emit event; a predefined event: RELOAD, STOP, START
or a custom string matching an event in a service
stanza, e.g: GW:UP, IFUP:IFNAME, IFDN:IFNAME. Where
IFNAME is the interface name, e.g. eth0
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
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
```
The `emit <EV>` command can be used to send events to Finit. Built-in
@@ -610,6 +618,11 @@ their command counterparts. The `reload` command reloads all `*.conf`
files in `/etc/finit.d/` *and* activates the changes, with `emit RELOAD`
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:
```shell
@@ -643,10 +656,10 @@ started.
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
service stanza: `service … <GW,IFUP:eth0>` to reload (`SIGHUP`) a
service when recieving the `"GW"` or `"IFUP:eth0"` strings. If a
service stanza: `service … <GW:UP,IFUP:eth0>` to reload (`SIGHUP`) 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
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
apply to `reload` and `runlevel` commands. I.e., when a service's
@@ -706,7 +719,8 @@ switches to configure:
* `--with-plugins=`: List of stock finit plugins to build and install.
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
of a standard Linux distribution with GNU tools and udev.
@@ -754,7 +768,7 @@ First, unpack the archive:
Then configure, build and install:
```shell
$ ./configure --with-plugins="initctl.so hwclock.so"
$ ./configure --with-plugins="initctl hwclock"
$ make
CC finit.o
CC conf.o
@@ -814,9 +828,9 @@ give the kernel the following extra command line:
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 compile-time tweaks:
Add `finit_debug`, or `--debug`, to the kernel command line to enable
debug messages. See the output from `configure --help` for more on
how to assist debugging.
```shell
init=/sbin/finit --debug
+27 -8
View File
@@ -30,6 +30,7 @@
#include <sys/socket.h>
#include <sys/un.h>
#include "config.h"
#include "finit.h"
#include "conf.h"
#include "helpers.h"
@@ -76,10 +77,10 @@ static int call(int (*action)(svc_t *), char *buf, size_t len)
token = strtok_r(input, " ", &pos);
while (token) {
svc_t *svc;
char *ptr = strchr(token, ':');
if (isdigit(token[0])) {
int job = atonum(token);
char *ptr = strchr(token, ':');
if (!ptr) {
svc = svc_job_iterator(1, job);
@@ -94,10 +95,15 @@ static int call(int (*action)(svc_t *), char *buf, size_t len)
}
} else {
svc = svc_named_iterator(1, token);
while (svc) {
result += action(svc);
svc = svc_named_iterator(0, token);
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)));
}
}
@@ -107,11 +113,17 @@ static int call(int (*action)(svc_t *), char *buf, size_t len)
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_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_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;
@@ -135,6 +147,7 @@ static int do_query_inetd(char *buf, size_t len)
return inetd_filter_str(&svc->inetd, buf, len);
}
#endif /* !INETD_DISABLED */
typedef struct {
char *event;
@@ -253,9 +266,13 @@ static void cb(uev_t *w, void *UNUSED(arg), int UNUSED(events))
case INIT_CMD_DEBUG:
debug = !debug;
if (debug)
verbose = 1;
else
verbose = quiet ? 0 : VERBOSE_MODE;
break;
case INIT_CMD_RELOAD:
case INIT_CMD_RELOAD: /* 'init q' and 'initctl reload' */
service_reload_dynamic();
break;
@@ -264,7 +281,7 @@ static void cb(uev_t *w, void *UNUSED(arg), int UNUSED(events))
break;
case INIT_CMD_STOP_SVC:
result = do_stop(rq.data, sizeof(rq.data));
result = do_pause(rq.data, sizeof(rq.data));
break;
case INIT_CMD_RELOAD_SVC:
@@ -275,9 +292,11 @@ static void cb(uev_t *w, void *UNUSED(arg), int UNUSED(events))
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));
+9 -5
View File
@@ -116,18 +116,21 @@ int conf_parse_runlevels(char *runlevels)
void conf_parse_events(svc_t *svc, char *events)
{
size_t i = 0;
char *ptr = events;
if (!events)
return;
char *ptr;
if (!svc) {
_e("Invalid service pointer");
return;
}
/* First character must be '!' if SIGHUP is not supported. */
/* By default we assume UNIX daemons support SIGHUP */
svc->sighup = 1;
if (!events)
return;
/* First character must be '!' if SIGHUP is not supported. */
ptr = events;
if (ptr[i] == '!') {
svc->sighup = 0;
ptr++;
@@ -142,6 +145,7 @@ void conf_parse_events(svc_t *svc, char *events)
return;
}
svc->state = SVC_CONDHALT_STATE;
strlcpy(svc->events, ptr, sizeof(svc->events));
}
Vendored
+4 -3
View File
@@ -22,6 +22,7 @@ defaults()
plugindir=${plugindir:="$libdir/$pdir"}
# The initctl FIFO, should probably be in /run, not /dev
fifo=${fifo:="/dev/initctl"}
random=${random:="/var/lib/urandom/random-seed"}
conf="finit.conf"
config=${config:="$sysconfdir/$conf"}
confdir=${confdir:="finit.d"}
@@ -149,9 +150,9 @@ usage()
echo " --with-fifo=FIFO FIFO for initctl plugin, default '$fifo'"
echo " --with-config=CONFIG Finit CONFIG file, default '\$sysconfdir/$conf'"
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 " systems, set this to /var/lib/urandom/random-seed"
echo " Default: none"
echo " --with-randomseed=SEED Seed /dev/urandom at boot from SEED. Usually found in"
echo " standard Linux systems at $random"
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 " files, or as built-in if --enable-static is given,"
echo " defaults to all plugins. Exclude extension!"
+16 -10
View File
@@ -140,9 +140,14 @@ int event_cache_if(char *ifname)
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)
@@ -152,7 +157,7 @@ int event_service_cond(char *events)
char temp[MAX_ARG_LEN];
/* No required events, condition satisfied */
if (validate_events(events))
if (!has_events(events))
return cond;
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 */
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;
}
if (change == 1) {
if (!service_enabled(svc, 1, NULL))
continue;
_d("Got event %s, (re)starting %s ...", svc->events, svc->cmd);
_d("%s matches <%s> %s (re)starting ...", msg, svc->events, svc->cmd);
if (!svc->pid) {
service_start(svc);
continue;
@@ -220,12 +227,11 @@ void event_dispatch(char *msg)
service_restart(svc);
} else { /* change == -1 */
if (svc->pid && !event_service_cond(svc->events))
service_stop(svc);
service_stop(svc, SVC_CONDHALT_STATE);
}
}
}
/**
* Local Variables:
* version-control: t
+7 -3
View File
@@ -43,9 +43,9 @@
int debug = 0;
int quiet = KERNEL_QUIET; /* Delayed disable of verbose mode. */
int verbose = VERBOSE_MODE;
int runlevel = 0; /* Bootstrap */
int runlevel = 0; /* Bootstrap 'S' */
int cfglevel = RUNLEVEL; /* Fallback if no configured runlevel */
int prevlevel = 0; /* HALT */
int prevlevel = -1;
char *sdown = NULL;
char *network = NULL;
char *username = NULL;
@@ -119,6 +119,10 @@ int main(int argc, char* argv[])
/*
* 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");
/*
@@ -214,7 +218,7 @@ int main(int argc, char* argv[])
tty_runlevel(runlevel);
/* Disable verbose mode, if selected */
if (quiet)
if (quiet && !debug)
verbose = 0;
/* Start new initctl API responder */
+23 -4
View File
@@ -84,17 +84,27 @@ int runlevel_get(void)
*/
char *runlevel_string(int levels)
{
int i, pos = 1;;
static char lvl[10] = "[]";
int i, pos = 1;
static char lvl[20];
memset(lvl, 0, sizeof(lvl));
lvl[0] = '[';
for (i = 0; i < 10; i++) {
if (ISSET(levels, i)) {
if (runlevel == i)
pos = strlcat(lvl, "\e[1m", sizeof(lvl));
if (i == 0)
lvl[pos++] = 'S';
else
lvl[pos++] = '0' + i;
if (runlevel == i)
pos = strlcat(lvl, "\e[0m", sizeof(lvl));
}
}
lvl[pos++] = ']';
lvl[pos] = 0;
@@ -132,6 +142,9 @@ void print(int action, const char *fmt, ...)
const char pending[] = " \e[1m[ \\/ ]\e[0m\n";
const char dots[] = " .....................................................................";
if (!verbose)
return;
if (fmt) {
va_start(ap, fmt);
len = vsnprintf(buf, sizeof(buf), fmt, ap);
@@ -174,27 +187,33 @@ int print_result(int fail)
return fail;
}
#ifndef ENABLE_STATIC
int getuser(char *username)
{
#ifdef ENABLE_STATIC
return fgetint("/etc/passwd", "x:\n", username);
#else
struct passwd *usr;
if (!username || (usr = getpwnam(username)) == NULL)
return -1;
return usr->pw_uid;
#endif
}
int getgroup(char *group)
{
#ifdef ENABLE_STATIC
return fgetint("/etc/group", "x:\n", group);
#else
struct group *grp;
if ((grp = getgrnam(group)) == NULL)
return -1;
return grp->gr_gid;
}
#endif
}
/* Signal safe sleep ... we get a lot of SIGCHLD at reboot */
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. */
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)
{
#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);
#endif
if (!*sv) {
const char *errstr;
static struct servent s;
@@ -238,8 +253,20 @@ static int getent(char *service, char *proto, struct servent **sv, struct protoe
*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);
#endif
if (!*pv) {
_e("Cannot find proto %s, skipping.", (*sv)->s_proto);
return errno = EINVAL;
+70 -27
View File
@@ -136,39 +136,70 @@ static int show_version(char *UNUSED(arg))
/* 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 *UNUSED(arg))
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("# Status PID Runlevels Service Description\n");
printf("====================================================================================\n");
}
for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) {
int inetd = svc_is_inetd(svc);
char jobid[10], args[512] = "";
struct init_request rq = {
.magic = INIT_MAGIC,
.cmd = INIT_CMD_QUERY_INETD,
};
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 %-6d %-9s ", jobid, svc_status(svc), svc->pid, runlevel_string(svc->runlevels));
printf("%-5s %7s %-6d ", jobid, svc_status(svc), svc->pid);
lvls = runlevel_string(svc->runlevels);
if (strchr(lvls, '\e'))
printf("%-18.18s ", lvls);
else
printf("%-10.10s ", lvls);
if (!verbose) {
printf("%-20s %s\n", svc->cmd, svc->desc);
continue;
}
if (inetd) {
#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))) {
@@ -184,7 +215,10 @@ static int show_status(char *UNUSED(arg))
}
printf("%s %s\n", svc->cmd, info);
} else {
}
else
#endif /* !INETD_DISABLED */
{
int i;
for (i = 1; i < MAX_NUM_SVC_ARGS; i++) {
@@ -203,22 +237,26 @@ static int usage(int rc)
{
fprintf(stderr, "Usage: %s [OPTIONS] <COMMAND>\n\n"
"Options:\n"
" -v, --verbose Verbose output\n"
" -h, --help This help text\n\n"
" -d, --debug Debug initctl (client)\n"
" -v, --verbose Verbose output\n"
" -h, --help This help text\n\n"
"Commands:\n"
" debug Toggle Finit debug\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"
" service stanza, e.g: GW, IFUP:IFNAME, IFDN:IFNAME, where\n"
" IFNAME is the interface name, e.g. eth0\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"
" start <JOB|NAME> Start stopped job or service\n"
" stop <JOB|NAME> Stop running job or service\n"
" restart <JOB|NAME> Restart (stop/start) job or service\n"
" reload <JOB|NAME> Reload (SIGHUP) job or service\n"
" version Show Finit version\n\n", __progname);
" debug Toggle Finit (daemon) debug\n"
" help This help text\n"
" emit <EV> Emit event; a predefined event: RELOAD, STOP, START\n"
" or a custom string matching an event in a service\n"
" stanza, e.g: GW:UP, IFUP:IFNAME, IFDN:IFNAME. Where\n"
" IFNAME is the interface name, e.g. eth0\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"
" 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"
" reload <JOB|NAME>[:ID] Reload (SIGHUP) service by job# or name\n"
" status <JOB|NAME>[:ID] Show status of a service by job# or name\n"
" show <JOB|NAME>[:ID] Alias to 'status <JOB|NAME>[:ID]'\n"
" version Show Finit version\n\n", __progname);
return rc;
}
@@ -241,17 +279,22 @@ int main(int argc, char *argv[])
};
struct option long_options[] = {
{"help", 0, NULL, 'h'},
{"debug", 0, NULL, 'd'},
{"verbose", 0, NULL, 'v'},
{NULL, 0, NULL, 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) {
case 'h':
case '?':
return usage(0);
case 'd':
debug = 1;
break;
case 'v':
verbose = 1;
break;
+1 -1
Submodule libite updated: bd9a618ea3...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);
#else
_d("Finit built statically, not loading plugins from %s ...", path);
if (verbose)
print_desc("Initializing plugins", NULL);
#endif /* ENABLE_STATIC */
/* Always initialize plugins */
init_plugins(ctx);
#ifndef ENABLE_STATIC
exit:
#endif
if (verbose)
print_result(fail);
+12
View File
@@ -14,7 +14,12 @@ endif
include ../common.mk
ifneq ($(STATIC), 1)
all: $(PLUGINS)
else
all:
@true
endif
clean:
-@$(RM) $(PLUGINS)
@@ -22,6 +27,7 @@ clean:
distclean:
-@$(RM) *.o *.so $(JUNK) $(DEPS)
ifneq ($(STATIC), 1)
install: all
@install -d $(DESTDIR)$(plugindir)
@for plugin in $(PLUGINS); do \
@@ -35,6 +41,12 @@ uninstall:
rm $(DESTDIR)$(plugindir)/$$plugin 2>/dev/null; \
done
-@rmdir $(DESTDIR)$(plugindir) 2>/dev/null
else
install:
@true
uninstall:
@true
endif
ifneq ($(MAKECMDGOALS),distclean)
-include $(DEPS)
+1
View File
@@ -39,6 +39,7 @@ static void restore(void *UNUSED(arg))
}
static plugin_t plugin = {
.name = __FILE__,
.hook[HOOK_BASEFS_UP] = {
.cb = restore
},
+3 -5
View File
@@ -24,15 +24,12 @@
#include <string.h>
#include <utmp.h>
#include "../config.h"
#include "../finit.h"
#include "../helpers.h"
#include "../plugin.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
* 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/misc", 0755);
makedir("/var/lib/alarm", 0755);
makedir("/var/lib/urandom",0755);
makedir("/var/lock", 0755);
makedir("/var/log", 0755);
makedir("/var/mail", 0755);
@@ -89,7 +87,7 @@ static void setup(void *UNUSED(arg))
}
static plugin_t plugin = {
.name = "bootmisc",
.name = __FILE__,
.hook[HOOK_BASEFS_UP] = {
.cb = setup
},
+1
View File
@@ -42,6 +42,7 @@ static void setup(void *UNUSED(arg))
}
static plugin_t plugin = {
.name = __FILE__,
.hook[HOOK_NETWORK_UP] = {
.cb = setup
},
+1
View File
@@ -41,6 +41,7 @@ static void restore(void *UNUSED(arg))
}
static plugin_t plugin = {
.name = __FILE__,
.hook[HOOK_BASEFS_UP] = {
.cb = restore
},
+1
View File
@@ -42,6 +42,7 @@
static void parse(void *arg, int fd, int events);
static plugin_t plugin = {
.name = __FILE__,
.io = {
.cb = parse,
.flags = PLUGIN_IO_READ,
+1
View File
@@ -180,6 +180,7 @@ static void nl_callback(void *UNUSED(arg), int sd, int UNUSED(events))
}
static plugin_t plugin = {
.name = __FILE__,
.io = {
.cb = nl_callback,
.flags = PLUGIN_IO_READ,
+1
View File
@@ -66,6 +66,7 @@ static void setup(void *UNUSED(arg))
}
static plugin_t plugin = {
.name = __FILE__,
.hook[HOOK_BASEFS_UP] = {
.cb = setup
},
+1 -1
View File
@@ -62,7 +62,7 @@ static int rfc868(int type)
}
static plugin_t plugin = {
.name = "time",
.name = "time", /* Must match the inetd /etc/services entry */
.inetd = {
.cmd = rfc868
}
+9 -2
View File
@@ -37,6 +37,7 @@
static void watcher(void *arg, int fd, int events);
static plugin_t plugin = {
.name = __FILE__,
.io = {
.cb = watcher,
.flags = PLUGIN_IO_READ,
@@ -45,7 +46,10 @@ static plugin_t plugin = {
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)
_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)))) {
if (-1 == len) {
if (errno == EINVAL)
setup();
if (errno == EINTR)
continue;
break;
break; /* Likely EAGAIN */
}
snprintf(name, sizeof(name), "/dev/%s", notified->name);
+42 -8
View File
@@ -22,29 +22,63 @@
*/
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h> /* gettimeofday() */
#include <sys/types.h>
#include "../config.h"
#include "../finit.h"
#include "libite/lite.h"
#include "../helpers.h"
#include "../plugin.h"
#include "libite/lite.h"
static void setup(void *UNUSED(arg))
{
#ifdef RANDOMSEED
copyfile(RANDOMSEED, "/dev/urandom", 0, 0);
unlink(RANDOMSEED);
if (!fexist(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);
copyfile("/dev/urandom", RANDOMSEED, 4096, 0);
print_desc("Saving random seed", NULL);
print_result(512 != copyfile("/dev/urandom", RANDOMSEED, 512, 0));
umask(0);
#endif
}
static plugin_t plugin = {
.hook[HOOK_BASEFS_UP] = {
.cb = setup
},
.name = __FILE__,
.hook[HOOK_BASEFS_UP] = { .cb = setup },
.hook[HOOK_SHUTDOWN] = { .cb = save },
.depends = { "bootmisc", }
};
+1
View File
@@ -54,6 +54,7 @@ static void setup(void *UNUSED(arg))
}
static plugin_t plugin = {
.name = __FILE__,
.hook[HOOK_NETWORK_UP] = {
.cb = setup
},
+113 -31
View File
@@ -41,11 +41,14 @@
#define RESPAWN_MAX 10 /* Prevent endless respawn of faulty services. */
static int dyn_stop_cnt = 0;
static int is_norespawn (void);
static void restart_lost_procs (void);
static void svc_dance (svc_t *svc);
#ifndef INETD_DISABLED
static svc_t *find_inetd_svc (char *path, char *service, char *proto);
#endif
/**
* 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 cmd = SVC_START; /* Default to start, since listed in finit.conf */
if (!svc) {
errno = EINVAL;
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.
*/
_d("Checking %s runlevel %d and events %s", svc->cmd, runlevel, svc->events);
if (runlevel && !event_service_cond(svc->events))
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? */
if (svc->cb) {
int status;
@@ -122,8 +133,10 @@ svc_cmd_t service_enabled(svc_t *svc, int event, void *arg)
}
/* Callback normally exits here. */
if (WIFEXITED(status))
return WEXITSTATUS(status);
if (WIFEXITED(status)) {
svc_cmd_t tmp = WEXITSTATUS(status);
return tmp == SVC_START ? cmd : tmp;
}
/* Check for SEGFAULT or other error ... */
if (WIFSIGNALED(status) && WCOREDUMP(status))
@@ -134,8 +147,13 @@ svc_cmd_t service_enabled(svc_t *svc, int event, void *arg)
return SVC_STOP;
}
/* No service plugin, default to start, since listed in finit.conf */
return SVC_START;
_d("%s => %s", svc->cmd, (cmd == SVC_START
? "SVC_START"
: (cmd == SVC_RELOAD
? "SVC_RELOAD"
: "SVC_STOP")));
return cmd;
}
/* Remember: service_enabled() must be called before calling service_start() */
@@ -294,6 +312,7 @@ int service_start(svc_t *svc)
exit(status);
}
svc->pid = pid;
svc->state = SVC_RUNNING_STATE;
if (svc_is_inetd(svc)) {
if (svc->inetd.type == SOCK_STREAM)
@@ -315,9 +334,9 @@ int service_start(svc_t *svc)
return 0;
}
int service_stop(svc_t *svc)
int service_stop(svc_t *svc, int state)
{
int res = 1;
int res = 0;
if (!svc)
return 1;
@@ -331,6 +350,10 @@ int service_stop(svc_t *svc)
if (SVC_TYPE_SERVICE != svc->type)
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 (runlevel != 1 && verbose)
print_desc("Stopping ", svc->desc);
@@ -340,7 +363,8 @@ int service_stop(svc_t *svc)
if (runlevel != 1 && verbose)
print_result(res);
exit:
svc->pid = 0;
if (!res)
svc->state = state;
svc->restart_counter = 0;
return res;
@@ -363,8 +387,36 @@ void service_start_dynamic(void)
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--;
_d("dyn_stop_cnt %d", 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 */
service_start_dynamic();
}
return 1;
}
/**
* 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)
{
@@ -372,31 +424,48 @@ void service_stop_dynamic(void)
_d("Stopping disabled/removed services ...");
for (svc = svc_dynamic_iterator(1); svc; svc = svc_dynamic_iterator(0)) {
if (svc_is_changed(svc))
service_stop(svc);
if (svc_is_changed(svc) && svc->pid) {
svc_state_t new_state = SVC_RELOAD_STATE;
if (svc_is_removed(svc))
new_state = SVC_HALTED_STATE;
if (!svc_has_sighup(svc))
dyn_stop_cnt++;
_d("Marking service %s as state %d", svc->cmd, new_state);
service_stop(svc, new_state);
}
}
_d("All disabled/removed services have been stoppped, calling reconf hooks ...");
plugin_run_hooks(HOOK_SVC_RECONF); /* Reconfigure HW/VLANs/etc here */
/* Check if we need to collect any services before calling user HOOK */
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
* so that the service monitor doesn't attempt to restart it!
* Unfortunately we cannot call service_start() here because we must
* 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 result = 0;
if (!svc)
return 1;
result += service_stop(svc);
sleep(1);
result += service_start(svc);
/* Ignore if finit is SIGSTOP'ed */
if (is_norespawn())
return 0;
return result;
svc->restart_counter = 0;
return service_stop(svc, SVC_RESTART_STATE);
}
/**
@@ -415,16 +484,15 @@ int service_reload(svc_t *svc)
if (is_norespawn())
return 0;
if (!svc) {
_e("Failed, no svc pointer.");
if (!svc)
return 1;
}
if (svc->pid <= 1) {
_d("Bad PID %d for %s, SIGHUP", svc->pid, svc->cmd);
svc->pid = 0;
return 1;
}
svc->state = SVC_RUNNING_STATE;
_d("Sending SIGHUP to PID %d", svc->pid);
return kill(svc->pid, SIGHUP);
@@ -445,8 +513,12 @@ void service_reload_dynamic(void)
/* Then stop any disabled/removed services and non-reloadable */
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 +555,12 @@ void service_runlevel(int newlevel)
inetd_stop(&svc->inetd);
else
#endif
service_stop(svc);
service_stop(svc, SVC_HALTED_STATE);
}
/* ... or disabled/removed services from /etc/finit.d/ */
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 ... */
@@ -528,7 +600,8 @@ void service_runlevel(int newlevel)
else
erase("/etc/nologin");
if (0 != prevlevel)
/* No TTYs run at bootstrap, they have a delayed start. */
if (prevlevel > 0)
tty_runlevel(runlevel);
}
@@ -733,6 +806,7 @@ int service_register(int type, char *line, time_t mtime, char *username)
if (svc_is_inetd(svc)) {
char *iface, *name = service;
svc->state = SVC_WAITING_STATE;
if (svc->inetd.cmd && plugin)
name = plugin->name;
@@ -762,7 +836,8 @@ int service_register(int type, char *line, time_t mtime, char *username)
void service_unregister(svc_t *svc)
{
service_stop(svc);
if (svc->state != SVC_HALTED_STATE)
_e("Failed stopping %s, removing anyway from list of monitored services.", svc->cmd);
svc_del(svc);
}
@@ -798,6 +873,9 @@ void service_monitor(pid_t lost)
if (lost != svc->pid)
continue;
if (!prevlevel && svc_clean_bootstrap(svc))
continue;
if (SVC_TYPE_SERVICE != svc->type) {
svc->pid = 0;
continue;
@@ -808,6 +886,10 @@ void service_monitor(pid_t lost)
/* No longer running, update books. */
svc->pid = 0;
/* Check if we're still collecting stopped dynamic services */
if (service_stop_done(svc))
break;
if (sig_stopped()) {
_e("Stopped, not respawning killed processes.");
break;
@@ -861,7 +943,7 @@ static void svc_dance(svc_t *svc)
if (svc->pid) {
if (SVC_STOP == cmd)
service_stop(svc);
service_stop(svc, SVC_HALTED_STATE);
else if (SVC_RELOAD == cmd)
service_reload(svc);
} 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);
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_stop_dynamic (void);
int service_restart (svc_t *svc);
+12
View File
@@ -38,12 +38,14 @@
* It activates the kbrequest action.
*/
#include <sched.h>
#include <string.h> /* strerror() */
#include <sys/reboot.h>
#include <sys/wait.h>
#include "finit.h"
#include "conf.h"
#include "config.h"
#include "helpers.h"
#include "plugin.h"
#include "private.h"
@@ -64,6 +66,15 @@ void do_shutdown(int sig)
if (sdown)
run_interactive(sdown, "Calling shutdown hook: %s", sdown);
/* If we enabled terse mode at boot, restore to previous setting at shutdown */
if (quiet) {
verbose = VERBOSE_MODE;
if (verbose) {
sched_yield();
fputs("\n", stderr);
}
}
/* Call all shutdown hooks before rebooting... */
plugin_run_hooks(HOOK_SHUTDOWN);
@@ -96,6 +107,7 @@ void do_shutdown(int sig)
*/
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();
}
+70 -5
View File
@@ -310,6 +310,33 @@ svc_t *svc_find_by_jobid(int job, int id)
return NULL;
}
/**
* svc_find_by_nameid - Find an service object by its basename:ID
* @name: Process name to match
* @id: Instance id
*
* Returns:
* A pointer to an &svc_t object, or %NULL if not found.
*/
svc_t *svc_find_by_nameid(char *name, int id)
{
char *ptr;
svc_t *svc;
for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) {
ptr = strrchr(svc->cmd, '/');
if (ptr)
ptr++;
else
ptr = svc->cmd;
if (svc->id == id && !strcmp(name, ptr))
return svc;
}
return NULL;
}
/**
* svc_mark_dynamic - Mark dynamically loaded services for deletion.
*
@@ -359,18 +386,56 @@ void svc_clean_dynamic(void (*cb)(svc_t *))
}
}
/**
* svc_clean_bootstrap - Remove bootstrap-only services after boot
* @svc: Pointer to &svc_t object
*
* Returns:
* %TRUE(1) if object was bootstrap-only, otherwise %FALSE(0)
*/
int svc_clean_bootstrap(svc_t *svc)
{
if (!ISOTHER(svc->runlevels, 0)) {
svc->pid = 0;
svc_del(svc);
return 1;
}
return 0;
}
char *svc_status(svc_t *svc)
{
if (svc->pid)
return "running";
if (!svc_in_runlevel(svc, runlevel))
return "halted";
if (svc_is_inetd(svc))
switch (svc->state) {
case SVC_WAITING_STATE:
return "waiting";
return "stopped";
case SVC_PAUSED_STATE:
return "stopped";
case SVC_CONDHALT_STATE:
return "nocond";
case SVC_RESTART_STATE:
return "restart";
case SVC_RELOAD_STATE:
return "reload";
case SVC_RUNNING_STATE:
if (svc->pid)
return "running";
/* Fall through */
case SVC_HALTED_STATE:
default:
break;
}
return "halted";
}
/* Same base service, return unique ID */
+15 -1
View File
@@ -40,12 +40,22 @@ typedef enum {
typedef enum {
SVC_TYPE_FREE = 0, /* Free to allocate */
SVC_TYPE_SERVICE , /* Monitored, will be respawned */
SVC_TYPE_SERVICE, /* Monitored, will be respawned */
SVC_TYPE_TASK, /* One-shot, runs in parallell */
SVC_TYPE_RUN, /* Like task, but wait for completion */
SVC_TYPE_INETD /* Classic inetd service */
} 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 MAX_ARG_LEN 64
#define MAX_STR_LEN 64
@@ -63,6 +73,7 @@ typedef struct svc {
/* Service details */
pid_t pid;
svc_state_t state; /* Paused, Reloading, Restart, Running, ... */
svc_type_t type;
time_t mtime; /* Modification time for .conf from /etc/finit.d/ */
int dirty; /* Set if old mtime != new mtime => reloaded,
@@ -120,6 +131,7 @@ int svc_del (svc_t *svc);
svc_t *svc_find (char *cmd, int id);
svc_t *svc_find_by_pid (pid_t pid);
svc_t *svc_find_by_jobid (int job, int id);
svc_t *svc_find_by_nameid (char *name, int id);
svc_t *svc_iterator (int first);
svc_t *svc_inetd_iterator (int first);
@@ -133,12 +145,14 @@ void svc_foreach_dynamic (void (*cb)(svc_t *));
void svc_mark_dynamic (void);
void svc_check_dirty (svc_t *svc, time_t mtime);
void svc_clean_dynamic (void (*cb)(svc_t *));
int svc_clean_bootstrap (svc_t *svc);
char *svc_status (svc_t *svc);
int svc_next_id (char *cmd);
int svc_is_unique (svc_t *svc);
static inline int svc_in_runlevel(svc_t *svc, int runlevel) { return svc && ISSET(svc->runlevels, runlevel); }
static inline int svc_has_sighup(svc_t *svc) { return svc && 0 != svc->sighup; }
static inline int svc_is_dynamic(svc_t *svc) { return svc && 0 != svc->mtime; }
static inline int svc_is_removed(svc_t *svc) { return svc && -1 == svc->dirty; }
+2 -1
View File
@@ -25,9 +25,10 @@
#ifndef FINIT_TTY_H_
#define FINIT_TTY_H_
#include <limits.h>
#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 {
char *name;