mirror of
https://github.com/troglobit/finit.git
synced 2026-10-12 10:12:32 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8218fff7e5 | ||
|
|
263e23a0df | ||
|
|
1f88e1ff8a | ||
|
|
b4ccc8b008 | ||
|
|
8df2b7b6e9 | ||
|
|
8073f7cf27 | ||
|
|
e303e1f833 | ||
|
|
3ea4be9343 | ||
|
|
d8188428ed | ||
|
|
d9f1882204 | ||
|
|
4d899851cc | ||
|
|
ad8feca3e7 | ||
|
|
7569c479b8 | ||
|
|
e7db6c6ac6 | ||
|
|
f12535dc19 | ||
|
|
b19ea16e9d | ||
|
|
eb59155dad | ||
|
|
f38dfaf2dc | ||
|
|
4ada42f380 | ||
|
|
924bf041bc | ||
|
|
b1d57d6828 | ||
|
|
87f9b94b42 | ||
|
|
c8f0b97d0f | ||
|
|
f902505b5d | ||
|
|
a6b78d57c0 | ||
|
|
a33478d563 | ||
|
|
369fcf2100 | ||
|
|
b2c5e97417 | ||
|
|
8725200260 | ||
|
|
58980c72fa | ||
|
|
bcc70ec774 | ||
|
|
44579cc089 | ||
|
|
da361f460d |
+56
-1
@@ -1,7 +1,61 @@
|
||||
Change Log
|
||||
==========
|
||||
|
||||
All notable changes to the project are documented in this file.
|
||||
All relevant changes are documented in this file.
|
||||
|
||||
[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 +74,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
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
uninstall-exec uninstall-data uninstall-dev
|
||||
|
||||
#VERSION = $(shell git tag -l | tail -1)
|
||||
VERSION = 2.1
|
||||
VERSION = 2.3
|
||||
NAME = finit
|
||||
PKG = $(NAME)-$(VERSION)
|
||||
DEV = $(NAME)-dev
|
||||
|
||||
@@ -586,22 +586,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 +613,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 +651,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 +714,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 +763,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
|
||||
|
||||
@@ -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;
|
||||
@@ -255,7 +268,7 @@ static void cb(uev_t *w, void *UNUSED(arg), int UNUSED(events))
|
||||
debug = !debug;
|
||||
break;
|
||||
|
||||
case INIT_CMD_RELOAD:
|
||||
case INIT_CMD_RELOAD: /* 'init q' and 'initctl reload' */
|
||||
service_reload_dynamic();
|
||||
break;
|
||||
|
||||
@@ -264,7 +277,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 +288,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));
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -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!"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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");
|
||||
|
||||
/*
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -174,27 +184,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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -144,31 +144,37 @@ static int show_status(char *UNUSED(arg))
|
||||
runlevel = runlevel_get();
|
||||
|
||||
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 +190,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 +212,24 @@ 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"
|
||||
" version Show Finit version\n\n", __progname);
|
||||
|
||||
return rc;
|
||||
}
|
||||
@@ -241,17 +252,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
@@ -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);
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -39,6 +39,7 @@ static void restore(void *UNUSED(arg))
|
||||
}
|
||||
|
||||
static plugin_t plugin = {
|
||||
.name = __FILE__,
|
||||
.hook[HOOK_BASEFS_UP] = {
|
||||
.cb = restore
|
||||
},
|
||||
|
||||
+3
-5
@@ -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
|
||||
},
|
||||
|
||||
@@ -42,6 +42,7 @@ static void setup(void *UNUSED(arg))
|
||||
}
|
||||
|
||||
static plugin_t plugin = {
|
||||
.name = __FILE__,
|
||||
.hook[HOOK_NETWORK_UP] = {
|
||||
.cb = setup
|
||||
},
|
||||
|
||||
@@ -41,6 +41,7 @@ static void restore(void *UNUSED(arg))
|
||||
}
|
||||
|
||||
static plugin_t plugin = {
|
||||
.name = __FILE__,
|
||||
.hook[HOOK_BASEFS_UP] = {
|
||||
.cb = restore
|
||||
},
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -66,6 +66,7 @@ static void setup(void *UNUSED(arg))
|
||||
}
|
||||
|
||||
static plugin_t plugin = {
|
||||
.name = __FILE__,
|
||||
.hook[HOOK_BASEFS_UP] = {
|
||||
.cb = setup
|
||||
},
|
||||
|
||||
+1
-1
@@ -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
@@ -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
@@ -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", }
|
||||
};
|
||||
|
||||
|
||||
@@ -54,6 +54,7 @@ static void setup(void *UNUSED(arg))
|
||||
}
|
||||
|
||||
static plugin_t plugin = {
|
||||
.name = __FILE__,
|
||||
.hook[HOOK_NETWORK_UP] = {
|
||||
.cb = setup
|
||||
},
|
||||
|
||||
@@ -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--;
|
||||
|
||||
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 && svc->state == SVC_RELOAD_STATE)
|
||||
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,46 @@ 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;
|
||||
|
||||
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 +482,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 +511,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 +553,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 +598,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 +804,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 +834,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 +871,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 +884,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 +941,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 {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -96,6 +96,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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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";
|
||||
return "stopped";
|
||||
|
||||
if (svc_is_inetd(svc))
|
||||
switch (svc->state) {
|
||||
case SVC_WAITING_STATE:
|
||||
return "waiting";
|
||||
|
||||
return "stopped";
|
||||
case SVC_PAUSED_STATE:
|
||||
return "paused";
|
||||
|
||||
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 */
|
||||
|
||||
@@ -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,6 +145,7 @@ 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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user