mirror of
https://github.com/troglobit/finit.git
synced 2026-11-01 13:10:32 +00:00
Add support for adding/removing services from /etc/finit.d at runtime.
This patch adds support for adding and removing services from Finit at runtime. Configuration file stanzas for service, run and task may now be written to files in /etc/finit.d/*.conf, using the exact same syntax as before in /etc/finit.conf. When a file is added, removed or modified the user may simply SIGHUP Finit (PID 1) to activate the changes. Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
This commit is contained in:
1 parent
24051ab2fb
commit
687f52b0b5
10 files changed
+454
-233
No files matched your search
@@ -12,6 +12,7 @@ Table of Contents
|
|||||||
* [Features](#features)
|
* [Features](#features)
|
||||||
* [/etc/finit.conf](#etcfinitconf)
|
* [/etc/finit.conf](#etcfinitconf)
|
||||||
* [/etc/finit.d](#etcfinitd)
|
* [/etc/finit.d](#etcfinitd)
|
||||||
|
* [Runparts](#runparts)
|
||||||
* [Bootstrap](#bootstrap)
|
* [Bootstrap](#bootstrap)
|
||||||
* [Runlevels](#runlevels)
|
* [Runlevels](#runlevels)
|
||||||
* [Inetd](#inetd)
|
* [Inetd](#inetd)
|
||||||
@@ -45,7 +46,7 @@ of processes to provide a very basic bootstrap written entirely in C.
|
|||||||
Hence, there is no `/etc/init.d/rcS` script, or similar, instead Finit
|
Hence, there is no `/etc/init.d/rcS` script, or similar, instead Finit
|
||||||
reads its configuration from [/etc/finit.conf](#etcfinitconf). This
|
reads its configuration from [/etc/finit.conf](#etcfinitconf). This
|
||||||
file details what kernel modules to load, programs to run, daemons to
|
file details what kernel modules to load, programs to run, daemons to
|
||||||
supervise, and services to launch on demand.
|
supervise, and inetd services to launch on demand.
|
||||||
|
|
||||||
See [TroglOS][9] for an example of how to boot a small embedded system
|
See [TroglOS][9] for an example of how to boot a small embedded system
|
||||||
with Finit.
|
with Finit.
|
||||||
@@ -159,15 +160,15 @@ Syntax:
|
|||||||
Finit does not output this text on the console when launching inetd
|
Finit does not output this text on the console when launching inetd
|
||||||
services. Instead this text is sent to syslog.
|
services. Instead this text is sent to syslog.
|
||||||
|
|
||||||
* `runparts <PATH>`
|
* `runparts <DIR>`
|
||||||
|
|
||||||
Call run-parts(8) on a directory other than default ``/etc/finit.d``
|
Call run-parts(8) on a directory to run start scripts. All executable
|
||||||
|
files, or scripts, in the directory are called, in alphabetic order.
|
||||||
|
|
||||||
* `include <CONF>`
|
* `include <CONF>`
|
||||||
|
|
||||||
Include another configuration file, ``/etc/finit.d``, or runparts path
|
Include another configuration file. If the file is not an absolute
|
||||||
is prepended to file if the file is not found or an absolute path is
|
path ``/etc/finit.d`` is prepended.
|
||||||
not given
|
|
||||||
|
|
||||||
* `tty [LVLS] <DEV | /path/to/cmd [args]>`
|
* `tty [LVLS] <DEV | /path/to/cmd [args]>`
|
||||||
|
|
||||||
@@ -209,8 +210,37 @@ the `/path/to/cmd` should be executed with. Simply prefix the path with
|
|||||||
/etc/finit.d
|
/etc/finit.d
|
||||||
------------
|
------------
|
||||||
|
|
||||||
|
Finit supports changes to the overall system configuration at runtime.
|
||||||
|
For this purpose the (configurable) directory `/etc/finit.d` is used.
|
||||||
|
Here you can put configuration file snippets, one per service if you
|
||||||
|
like, which are all sourced automatically by finit at boot when loading
|
||||||
|
the static configuration from `/etc/finit.conf`. This is the default
|
||||||
|
behavior, so no include directives are necessary.
|
||||||
|
|
||||||
|
To add a new service, simply drop a `.conf` file in `/etc/finit.d` and
|
||||||
|
send `SIGHUP` to finit, or call `init q`. Any service read from this
|
||||||
|
directory is flagged as a dynamic service, so changes to their .conf
|
||||||
|
files, or even removal of the files, is detected at `SIGHUP`.
|
||||||
|
|
||||||
|
- If a service's .conf file has been removed, the service is stopped.
|
||||||
|
- If the file has changed the service is reloaded, stopped and
|
||||||
|
restarted.
|
||||||
|
- If it is a new service, it is started -- respecting runlevels and
|
||||||
|
callbacks.
|
||||||
|
|
||||||
|
The `/etc/finit.d` directory was previously the default Finit `runparts`
|
||||||
|
directory. Finit no longer has a default runparts, so make sure to
|
||||||
|
update your setup, or the finit configuration, accordingly.
|
||||||
|
|
||||||
|
**Note:** Configurations read from `/etc/finit.d` are read *after*
|
||||||
|
initial bootstrap, runlevel S(1).
|
||||||
|
|
||||||
|
|
||||||
|
Runparts
|
||||||
|
--------
|
||||||
|
|
||||||
At the end of the boot, when networking and all services are up, finit
|
At the end of the boot, when networking and all services are up, finit
|
||||||
calls its built-in [run-parts(8)] on the `/etc/finit.d/` directory, if
|
calls its built-in [run-parts(8)] on the `runparts <DIR>` directory, if
|
||||||
it exists. Similar to how the `/ec/rc.local` file works in most other
|
it exists. Similar to how the `/ec/rc.local` file works in most other
|
||||||
init daemons, only finit runs a directory of scripts. This replaces the
|
init daemons, only finit runs a directory of scripts. This replaces the
|
||||||
earlier support for a `/usr/sbin/services.sh` script in the original
|
earlier support for a `/usr/sbin/services.sh` script in the original
|
||||||
|
|||||||
@@ -18,9 +18,7 @@ very low dependency on external packages.
|
|||||||
General
|
General
|
||||||
-------
|
-------
|
||||||
|
|
||||||
* Make it possible to at least reload .conf files in `/etc/finit.d/` --
|
* Add support for instances, e.g. to monitor several DHCP clients.
|
||||||
At first all we need to support is the service directive, All other
|
|
||||||
directives, read from `/etc/finit.conf`, can remain static.
|
|
||||||
* Make initctl synchroneous, don't let `init 1` return until finit
|
* Make initctl synchroneous, don't let `init 1` return until finit
|
||||||
has successfully entered runlevel 1, all proceses have been stopped.
|
has successfully entered runlevel 1, all proceses have been stopped.
|
||||||
* Add `!` or `[wait <pidfile>]` to service directive to let finit pause
|
* Add `!` or `[wait <pidfile>]` to service directive to let finit pause
|
||||||
@@ -31,10 +29,6 @@ General
|
|||||||
and `RELOAD` on `STDOUT` from a script ... call it for instance
|
and `RELOAD` on `STDOUT` from a script ... call it for instance
|
||||||
`.monitor=` in `svc_t` ... the script named as the basename of the
|
`.monitor=` in `svc_t` ... the script named as the basename of the
|
||||||
service it monitors + `.sh`.
|
service it monitors + `.sh`.
|
||||||
* The `runparts` directive may need to be deprecated, or to have its
|
|
||||||
semantics changed. We need `/etc/finit.d/` for extending `finit.conf`
|
|
||||||
-- if not possible, then maybe filter out the service monitor scripts
|
|
||||||
before running the scripts?
|
|
||||||
* Add compile-time supoprt for running `/bin/sh` instead of `getty`
|
* Add compile-time supoprt for running `/bin/sh` instead of `getty`
|
||||||
* Add support for `init <q | reload-configuration>` and `SIGHUP` to
|
* Add support for `init <q | reload-configuration>` and `SIGHUP` to
|
||||||
have finit reload its `finit.conf`, but also
|
have finit reload its `finit.conf`, but also
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* Parser for finit.conf
|
/* Parser for finit.conf
|
||||||
*
|
*
|
||||||
* Copyright (c) 2012 Joachim Nilsson <troglobit@gmail.com>
|
* Copyright (c) 2012-2015 Joachim Nilsson <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -22,6 +22,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
#include <dirent.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
@@ -33,6 +34,9 @@
|
|||||||
#define MATCH_CMD(l, c, x) \
|
#define MATCH_CMD(l, c, x) \
|
||||||
(!strncasecmp(l, c, strlen(c)) && (x = (l) + strlen(c)))
|
(!strncasecmp(l, c, strlen(c)) && (x = (l) + strlen(c)))
|
||||||
|
|
||||||
|
static int parse_conf(char *file);
|
||||||
|
|
||||||
|
|
||||||
static char *strip_line(char *line)
|
static char *strip_line(char *line)
|
||||||
{
|
{
|
||||||
char *ptr;
|
char *ptr;
|
||||||
@@ -86,13 +90,197 @@ int parse_runlevels(char *runlevels)
|
|||||||
return bitmask;
|
return bitmask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void parse_static(char *line)
|
||||||
|
{
|
||||||
|
char *x;
|
||||||
|
char cmd[CMD_SIZE];
|
||||||
|
|
||||||
|
/* Do this before mounting / read-write
|
||||||
|
* XXX: Move to plugin which checks /etc/fstab instead */
|
||||||
|
if (MATCH_CMD(line, "check ", x)) {
|
||||||
|
char *dev = strip_line(x);
|
||||||
|
|
||||||
|
strcpy(cmd, "/sbin/fsck -C -a ");
|
||||||
|
strlcat(cmd, dev, sizeof(cmd));
|
||||||
|
run_interactive(cmd, "Checking file system %s", dev);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (MATCH_CMD(line, "user ", x)) {
|
||||||
|
if (username) free(username);
|
||||||
|
username = strdup(strip_line(x));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (MATCH_CMD(line, "host ", x)) {
|
||||||
|
if (hostname) free(hostname);
|
||||||
|
hostname = strdup(strip_line(x));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (MATCH_CMD(line, "module ", x)) {
|
||||||
|
char *mod = strip_line(x);
|
||||||
|
|
||||||
|
strcpy(cmd, "/sbin/modprobe ");
|
||||||
|
strlcat(cmd, mod, sizeof(cmd));
|
||||||
|
run_interactive(cmd, "Loading kernel module %s", mod);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (MATCH_CMD(line, "mknod ", x)) {
|
||||||
|
char *dev = strip_line(x);
|
||||||
|
|
||||||
|
strcpy(cmd, "/bin/mknod ");
|
||||||
|
strlcat(cmd, dev, sizeof(cmd));
|
||||||
|
run_interactive(cmd, "Creating device node %s", dev);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (MATCH_CMD(line, "network ", x)) {
|
||||||
|
if (network) free(network);
|
||||||
|
network = strdup(strip_line(x));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This is the directory from which executable scripts and
|
||||||
|
* any finit include files are read, default /etc/finit.d/ */
|
||||||
|
if (MATCH_CMD(line, "runparts ", x)) {
|
||||||
|
if (runparts) free(runparts);
|
||||||
|
runparts = strdup(strip_line(x));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse any include file, use rcsd if absolute path not given */
|
||||||
|
if (MATCH_CMD(line, "include ", x)) {
|
||||||
|
char *file = strip_line(x);
|
||||||
|
|
||||||
|
strlcpy(cmd, file, sizeof(cmd));
|
||||||
|
if (!fexist(cmd)) {
|
||||||
|
/* ... try /etc/finit.d/ as prefix */
|
||||||
|
snprintf(cmd, sizeof(cmd), "%s/%s", rcsd, file);
|
||||||
|
if (!fexist(cmd))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
parse_conf(cmd);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (MATCH_CMD(line, "startx ", x)) {
|
||||||
|
svc_register(SVC_TYPE_SERVICE, strip_line(x), 0, username);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (MATCH_CMD(line, "shutdown ", x)) {
|
||||||
|
if (sdown) free(sdown);
|
||||||
|
sdown = strdup(strip_line(x));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The desired runlevel to start when leaving
|
||||||
|
* bootstrap (S). Finit supports 1-9, but most
|
||||||
|
* systems only use 1-6, where 6 is reserved for
|
||||||
|
* reboot */
|
||||||
|
if (MATCH_CMD(line, "runlevel ", x)) {
|
||||||
|
char *token = strip_line(x);
|
||||||
|
const char *err = NULL;
|
||||||
|
|
||||||
|
cfglevel = strtonum(token, 1, 9, &err);
|
||||||
|
if (err)
|
||||||
|
cfglevel = RUNLEVEL;
|
||||||
|
if (cfglevel < 1 || cfglevel > 9 || cfglevel == 6)
|
||||||
|
cfglevel = 2; /* Fallback */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: Make console & tty dynamically loadable from /etc/finit.d */
|
||||||
|
if (MATCH_CMD(line, "console ", x)) {
|
||||||
|
if (console) free(console);
|
||||||
|
console = strdup(strip_line(x));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: Make console & tty dynamically loadable from /etc/finit.d */
|
||||||
|
if (MATCH_CMD(line, "tty ", x)) {
|
||||||
|
tty_register(strip_line(x));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void parse_dynamic(char *line, time_t mtime)
|
||||||
|
{
|
||||||
|
char *x;
|
||||||
|
|
||||||
|
/* Skip comments. */
|
||||||
|
if (MATCH_CMD(line, "#", x))
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Monitored daemon, will be respawned on exit, as
|
||||||
|
* long as the (optional) service callback returns
|
||||||
|
* non-zero */
|
||||||
|
if (MATCH_CMD(line, "service ", x)) {
|
||||||
|
svc_register(SVC_TYPE_SERVICE, x, mtime, NULL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* One-shot task, will not be respawned. Only runs if
|
||||||
|
* the (optional) service callback returns true */
|
||||||
|
if (MATCH_CMD(line, "task ", x)) {
|
||||||
|
svc_register(SVC_TYPE_TASK, x, mtime, NULL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Like task but waits for completion, useful w/ [S] */
|
||||||
|
if (MATCH_CMD(line, "run ", x)) {
|
||||||
|
svc_register(SVC_TYPE_RUN, x, mtime, NULL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Classic inetd service */
|
||||||
|
if (MATCH_CMD(line, "inetd ", x)) {
|
||||||
|
#ifndef INETD_DISABLED
|
||||||
|
svc_register(SVC_TYPE_INETD, x, mtime, NULL);
|
||||||
|
#else
|
||||||
|
_e("Finit built with inetd support disabled, cannot register service inetd %s!", x);
|
||||||
|
#endif
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int parse_conf_dynamic(char *file, time_t mtime)
|
||||||
|
{
|
||||||
|
FILE *fp = fopen(file, "r");
|
||||||
|
|
||||||
|
if (!fp) {
|
||||||
|
_pe("Failed opening %s", file);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!feof(fp)) {
|
||||||
|
char line[LINE_SIZE] = "";
|
||||||
|
|
||||||
|
if (!fgets(line, sizeof(line), fp))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
chomp(line);
|
||||||
|
_d("dyn conf: %s", line);
|
||||||
|
|
||||||
|
parse_dynamic(line, mtime);
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int parse_conf(char *file)
|
static int parse_conf(char *file)
|
||||||
{
|
{
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
char line[LINE_SIZE] = "";
|
char line[LINE_SIZE] = "";
|
||||||
char cmd[CMD_SIZE];
|
|
||||||
char *x;
|
char *x;
|
||||||
const char *err = NULL;
|
|
||||||
|
|
||||||
fp = fopen(file, "r");
|
fp = fopen(file, "r");
|
||||||
if (!fp)
|
if (!fp)
|
||||||
@@ -123,146 +311,10 @@ static int parse_conf(char *file)
|
|||||||
if (!fgets(line, sizeof(line), fp))
|
if (!fgets(line, sizeof(line), fp))
|
||||||
continue;
|
continue;
|
||||||
chomp(line);
|
chomp(line);
|
||||||
|
|
||||||
_d("conf: %s", line);
|
_d("conf: %s", line);
|
||||||
|
parse_static(line);
|
||||||
/* Skip comments. */
|
parse_dynamic(line, 0);
|
||||||
if (MATCH_CMD(line, "#", x))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* Do this before mounting / read-write
|
|
||||||
* XXX: Move to plugin which checks /etc/fstab instead */
|
|
||||||
if (MATCH_CMD(line, "check ", x)) {
|
|
||||||
char *dev = strip_line(x);
|
|
||||||
|
|
||||||
strcpy(cmd, "/sbin/fsck -C -a ");
|
|
||||||
strlcat(cmd, dev, sizeof(cmd));
|
|
||||||
run_interactive(cmd, "Checking file system %s", dev);
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (MATCH_CMD(line, "user ", x)) {
|
|
||||||
if (username) free(username);
|
|
||||||
username = strdup(strip_line(x));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (MATCH_CMD(line, "host ", x)) {
|
|
||||||
if (hostname) free(hostname);
|
|
||||||
hostname = strdup(strip_line(x));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (MATCH_CMD(line, "module ", x)) {
|
|
||||||
char *mod = strip_line(x);
|
|
||||||
|
|
||||||
strcpy(cmd, "/sbin/modprobe ");
|
|
||||||
strlcat(cmd, mod, sizeof(cmd));
|
|
||||||
run_interactive(cmd, "Loading kernel module %s", mod);
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (MATCH_CMD(line, "mknod ", x)) {
|
|
||||||
char *dev = strip_line(x);
|
|
||||||
|
|
||||||
strcpy(cmd, "/bin/mknod ");
|
|
||||||
strlcat(cmd, dev, sizeof(cmd));
|
|
||||||
run_interactive(cmd, "Creating device node %s", dev);
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (MATCH_CMD(line, "network ", x)) {
|
|
||||||
if (network) free(network);
|
|
||||||
network = strdup(strip_line(x));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
/* This is the directory from which executable scripts and
|
|
||||||
* any finit include files are read, default /etc/finit.d/ */
|
|
||||||
if (MATCH_CMD(line, "runparts ", x)) {
|
|
||||||
if (rcsd) free(rcsd);
|
|
||||||
rcsd = strdup(strip_line(x));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
/* Parse any include file, use rcsd if absolute path not given */
|
|
||||||
if (MATCH_CMD(line, "include ", x)) {
|
|
||||||
char *file = strip_line(x);
|
|
||||||
|
|
||||||
strlcpy(cmd, file, sizeof(cmd));
|
|
||||||
if (!fexist(cmd)) {
|
|
||||||
/* ... try /etc/finit.d/ as prefix */
|
|
||||||
snprintf(cmd, sizeof(cmd), "%s/%s", rcsd, file);
|
|
||||||
if (!fexist(cmd))
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
parse_conf(cmd);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (MATCH_CMD(line, "startx ", x)) {
|
|
||||||
svc_register(SVC_CMD_SERVICE, strip_line(x), username);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (MATCH_CMD(line, "shutdown ", x)) {
|
|
||||||
if (sdown) free(sdown);
|
|
||||||
sdown = strdup(strip_line(x));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The desired runlevel to start when leaving
|
|
||||||
* bootstrap (S). Finit supports 1-9, but most
|
|
||||||
* systems only use 1-6, where 6 is reserved for
|
|
||||||
* reboot */
|
|
||||||
if (MATCH_CMD(line, "runlevel ", x)) {
|
|
||||||
char *token = strip_line(x);
|
|
||||||
|
|
||||||
cfglevel = strtonum(token, 1, 9, &err);
|
|
||||||
if (err)
|
|
||||||
cfglevel = RUNLEVEL;
|
|
||||||
if (cfglevel < 1 || cfglevel > 9 || cfglevel == 6)
|
|
||||||
cfglevel = 2; /* Fallback */
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Monitored daemon, will be respawned on exit, as
|
|
||||||
* long as the (optional) service callback returns
|
|
||||||
* non-zero */
|
|
||||||
if (MATCH_CMD(line, "service ", x)) {
|
|
||||||
svc_register(SVC_CMD_SERVICE, x, NULL);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* One-shot task, will not be respawned. Only runs if
|
|
||||||
* the (optional) service callback returns true */
|
|
||||||
if (MATCH_CMD(line, "task ", x)) {
|
|
||||||
svc_register(SVC_CMD_TASK, x, NULL);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Like task but waits for completion, useful w/ [S] */
|
|
||||||
if (MATCH_CMD(line, "run ", x)) {
|
|
||||||
svc_register(SVC_CMD_RUN, x, NULL);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Classic inetd service */
|
|
||||||
if (MATCH_CMD(line, "inetd ", x)) {
|
|
||||||
#ifndef INETD_DISABLED
|
|
||||||
svc_register(SVC_CMD_INETD, x, NULL);
|
|
||||||
#else
|
|
||||||
_e("Finit built with inetd support disabled, cannot register service inetd %s!", x);
|
|
||||||
#endif
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (MATCH_CMD(line, "console ", x)) {
|
|
||||||
if (console) free(console);
|
|
||||||
console = strdup(strip_line(x));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (MATCH_CMD(line, "tty ", x)) {
|
|
||||||
tty_register(strip_line(x));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
@@ -270,13 +322,54 @@ static int parse_conf(char *file)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int parse_finit_d(char *dir)
|
||||||
|
{
|
||||||
|
int i, num;
|
||||||
|
struct dirent **e;
|
||||||
|
|
||||||
|
num = scandir(dir, &e, NULL, alphasort);
|
||||||
|
if (num < 0) {
|
||||||
|
_d("No files found in %s, skipping ...", dir);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < num; i++) {
|
||||||
|
char *name = e[i]->d_name;
|
||||||
|
char path[CMD_SIZE];
|
||||||
|
struct stat st;
|
||||||
|
|
||||||
|
snprintf(path, sizeof(path), "%s/%s", dir, name);
|
||||||
|
|
||||||
|
/* Check that it's an actual file ... */
|
||||||
|
if (stat(path, &st)) {
|
||||||
|
_d("Cannot even read .conf file %s, skipping ...", path);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (S_ISEXEC(st.st_mode) || S_ISDIR(st.st_mode))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Check that file ends with '.conf' */
|
||||||
|
if (strcmp(&path[strlen(path) - 5], ".conf")) {
|
||||||
|
_d("File %s is not a .conf, skipping ... ", path);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
parse_conf_dynamic(path, st.st_mtime);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (num--)
|
||||||
|
free(e[num]);
|
||||||
|
free(e);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int parse_finit_conf(char *file)
|
int parse_finit_conf(char *file)
|
||||||
{
|
{
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
username = strdup(DEFUSER);
|
username = strdup(DEFUSER);
|
||||||
hostname = strdup(DEFHOST);
|
hostname = strdup(DEFHOST);
|
||||||
rcsd = strdup(FINIT_RCSD);
|
|
||||||
|
|
||||||
result = parse_conf(file);
|
result = parse_conf(file);
|
||||||
if (!tty_num()) {
|
if (!tty_num()) {
|
||||||
|
|||||||
@@ -47,7 +47,8 @@ char *sdown = NULL;
|
|||||||
char *network = NULL;
|
char *network = NULL;
|
||||||
char *username = NULL;
|
char *username = NULL;
|
||||||
char *hostname = NULL;
|
char *hostname = NULL;
|
||||||
char *rcsd = NULL;
|
char *rcsd = FINIT_RCSD;
|
||||||
|
char *runparts = NULL;
|
||||||
char *console = NULL;
|
char *console = NULL;
|
||||||
|
|
||||||
uev_ctx_t *ctx = NULL; /* Main loop context */
|
uev_ctx_t *ctx = NULL; /* Main loop context */
|
||||||
@@ -262,19 +263,21 @@ int main(int argc, char* argv[])
|
|||||||
plugin_run_hooks(HOOK_NETWORK_UP);
|
plugin_run_hooks(HOOK_NETWORK_UP);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Start all tasks/services in the configured runlevel
|
* Load .conf files from /etc/finit.d and start all
|
||||||
|
* tasks/services in the configured runlevel
|
||||||
*/
|
*/
|
||||||
|
parse_finit_d(rcsd);
|
||||||
svc_runlevel(cfglevel);
|
svc_runlevel(cfglevel);
|
||||||
|
|
||||||
_d("Running svc up hooks ...");
|
_d("Running svc up hooks ...");
|
||||||
plugin_run_hooks(HOOK_SVC_UP);
|
plugin_run_hooks(HOOK_SVC_UP);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Run startup scripts in /etc/finit.d/, if any.
|
* Run startup scripts in the runparts directory, if any.
|
||||||
*/
|
*/
|
||||||
if (rcsd && fisdir(rcsd)) {
|
if (runparts && fisdir(runparts)) {
|
||||||
_d("Running startup scripts in %s ...", rcsd);
|
_d("Running startup scripts in %s ...", runparts);
|
||||||
run_parts(rcsd, NULL);
|
run_parts(runparts, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Hooks that should run at the very end */
|
/* Hooks that should run at the very end */
|
||||||
|
|||||||
+2
-2
@@ -33,8 +33,8 @@ service [2345] /sbin/klogd -n -- Kernel logging server
|
|||||||
service [2345] /sbin/syslogd -n -- Syslog server
|
service [2345] /sbin/syslogd -n -- Syslog server
|
||||||
service [3] /usr/sbin/gdm -- GNOME Display Manager
|
service [3] /usr/sbin/gdm -- GNOME Display Manager
|
||||||
|
|
||||||
# By default Finit looks for /etc/finit.d
|
# Run start scripts from this directory
|
||||||
# runparts /etc/finit.d
|
# runparts /etc/start.d
|
||||||
|
|
||||||
# Inetd services
|
# Inetd services
|
||||||
inetd time/udp wait [2345] internal -- UNIX rdate service
|
inetd time/udp wait [2345] internal -- UNIX rdate service
|
||||||
|
|||||||
@@ -89,17 +89,19 @@ struct init_request {
|
|||||||
extern int runlevel;
|
extern int runlevel;
|
||||||
extern int cfglevel;
|
extern int cfglevel;
|
||||||
extern int prevlevel;
|
extern int prevlevel;
|
||||||
|
extern char *rcsd;
|
||||||
extern char *sdown;
|
extern char *sdown;
|
||||||
extern char *network;
|
extern char *network;
|
||||||
extern char *hostname;
|
extern char *hostname;
|
||||||
extern char *username;
|
extern char *username;
|
||||||
extern char *rcsd;
|
extern char *runparts;
|
||||||
extern char *console;
|
extern char *console;
|
||||||
extern char *__progname;
|
extern char *__progname;
|
||||||
|
|
||||||
/* conf.c */
|
/* conf.c */
|
||||||
int parse_runlevels (char *runlevels);
|
int parse_runlevels (char *runlevels);
|
||||||
int parse_finit_conf (char *file);
|
int parse_finit_conf (char *file);
|
||||||
|
int parse_finit_d (char *dir);
|
||||||
|
|
||||||
#endif /* FINIT_H_ */
|
#endif /* FINIT_H_ */
|
||||||
|
|
||||||
|
|||||||
@@ -179,7 +179,7 @@ int inetd_respawn(pid_t pid)
|
|||||||
{
|
{
|
||||||
svc_t *svc = svc_find_by_pid(pid);
|
svc_t *svc = svc_find_by_pid(pid);
|
||||||
|
|
||||||
if (svc && SVC_CMD_INETD == svc->type) {
|
if (svc && SVC_TYPE_INETD == svc->type) {
|
||||||
inetd_t *inetd = &svc->inetd;
|
inetd_t *inetd = &svc->inetd;
|
||||||
|
|
||||||
svc->pid = 0;
|
svc->pid = 0;
|
||||||
@@ -481,7 +481,7 @@ int inetd_init(inetd_t *inetd, void *arg, char *ifname, char *port)
|
|||||||
inetd_filter_t *filter;
|
inetd_filter_t *filter;
|
||||||
|
|
||||||
/* Skip non-inetd services */
|
/* Skip non-inetd services */
|
||||||
if (svc->type != SVC_CMD_INETD)
|
if (svc->type != SVC_TYPE_INETD)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Skip ourselves */
|
/* Skip ourselves */
|
||||||
|
|||||||
@@ -48,7 +48,7 @@
|
|||||||
#include "sig.h"
|
#include "sig.h"
|
||||||
|
|
||||||
static int stopped = 0;
|
static int stopped = 0;
|
||||||
static uev_t sigint_watcher, sigpwr_watcher;
|
static uev_t sighup_watcher, sigint_watcher, sigpwr_watcher;
|
||||||
static uev_t sigchld_watcher, sigsegv_watcher;
|
static uev_t sigchld_watcher, sigsegv_watcher;
|
||||||
static uev_t sigstop_watcher, sigtstp_watcher, sigcont_watcher;
|
static uev_t sigstop_watcher, sigtstp_watcher, sigcont_watcher;
|
||||||
|
|
||||||
@@ -87,6 +87,24 @@ void do_shutdown(int sig)
|
|||||||
reboot(RB_POWER_OFF);
|
reboot(RB_POWER_OFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Reload .conf files in /etc/finit.d/
|
||||||
|
*/
|
||||||
|
static void sighup_cb(uev_ctx_t *UNUSED(ctx), uev_t *UNUSED(w), void *UNUSED(arg), int UNUSED(events))
|
||||||
|
{
|
||||||
|
/* Mark and sweep */
|
||||||
|
svc_mark_dynamic();
|
||||||
|
|
||||||
|
/* Reload all *.conf in /etc/finit.d/ */
|
||||||
|
parse_finit_d(rcsd);
|
||||||
|
|
||||||
|
/* Reload dirty services */
|
||||||
|
svc_reload_dynamic();
|
||||||
|
|
||||||
|
/* Cleanup stale services */
|
||||||
|
svc_cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Shut down on INT PWR
|
* Shut down on INT PWR
|
||||||
*/
|
*/
|
||||||
@@ -207,8 +225,8 @@ void sig_setup(uev_ctx_t *ctx)
|
|||||||
/* Some C APIs may need SIGALRM for implementing timers. */
|
/* Some C APIs may need SIGALRM for implementing timers. */
|
||||||
IGNSIG(sa, SIGALRM, 0);
|
IGNSIG(sa, SIGALRM, 0);
|
||||||
|
|
||||||
/* We don't have any /etc/inittab yet, reread finit.conf? */
|
/* /etc/inittab not supported yet, instead /etc/finit.d/ is scanned for *.conf */
|
||||||
IGNSIG(sa, SIGHUP, 0);
|
uev_signal_init(ctx, &sighup_watcher, sighup_cb, NULL, SIGHUP);
|
||||||
|
|
||||||
/* After initial bootstrap of Finit we call the service monitor to reap children */
|
/* After initial bootstrap of Finit we call the service monitor to reap children */
|
||||||
uev_signal_init(ctx, &sigchld_watcher, sigchld_cb, NULL, SIGCHLD);
|
uev_signal_init(ctx, &sigchld_watcher, sigchld_cb, NULL, SIGCHLD);
|
||||||
|
|||||||
@@ -40,7 +40,6 @@
|
|||||||
* by 3rd party APIs. Mostly because of the ability to, from the outside, query
|
* by 3rd party APIs. Mostly because of the ability to, from the outside, query
|
||||||
* liveness state of all daemons that should run. */
|
* liveness state of all daemons that should run. */
|
||||||
static int was_stopped = 0;
|
static int was_stopped = 0;
|
||||||
static int svc_counter = 0; /* Number of registered services to monitor. */
|
|
||||||
static svc_t *services = NULL; /* List of registered services, in shared memory. */
|
static svc_t *services = NULL; /* List of registered services, in shared memory. */
|
||||||
|
|
||||||
|
|
||||||
@@ -66,42 +65,37 @@ static void __connect_shm(void)
|
|||||||
*/
|
*/
|
||||||
svc_t *svc_new(void)
|
svc_t *svc_new(void)
|
||||||
{
|
{
|
||||||
svc_t *svc = NULL;
|
int i;
|
||||||
|
|
||||||
__connect_shm();
|
__connect_shm();
|
||||||
if (svc_counter >= 0 && svc_counter < MAX_NUM_SVC) {
|
for (i = 0; i < MAX_NUM_SVC; i++) {
|
||||||
svc = &services[svc_counter++];
|
svc_t *svc = &services[i];
|
||||||
memset(svc, 0, sizeof(*svc));
|
|
||||||
} else {
|
if (svc->type == SVC_TYPE_FREE) {
|
||||||
errno = ENOMEM;
|
memset(svc, 0, sizeof(*svc));
|
||||||
return NULL;
|
return svc;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return svc;
|
errno = ENOMEM;
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* svc_del - Delete a service object
|
* svc_del - Delete a service object
|
||||||
* @svc: Pointer to an &svc_t object
|
* @svc: Pointer to an &svc_t object
|
||||||
*
|
*
|
||||||
* Note, this function is not safe for public use. Should only be used
|
|
||||||
* by this module until the storage of svc_t's has been refactored!
|
|
||||||
*
|
|
||||||
* Returns:
|
* Returns:
|
||||||
* Always succeeds, returning POSIX OK(0).
|
* Always succeeds, returning POSIX OK(0).
|
||||||
*/
|
*/
|
||||||
int svc_del(svc_t *svc)
|
int svc_del(svc_t *svc)
|
||||||
{
|
{
|
||||||
if (svc_counter >= 0 && svc_counter < MAX_NUM_SVC) {
|
svc->type = SVC_TYPE_FREE;
|
||||||
svc = &services[--svc_counter];
|
|
||||||
memset(svc, 0, sizeof(*svc));
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* svc_iterator - Iterates over all registered services.
|
* svc_iterator - Naive iterator over all registered services.
|
||||||
* @first: Get first &svc_t object, or next until end.
|
* @first: Get first &svc_t object, or next until end.
|
||||||
*
|
*
|
||||||
* Returns:
|
* Returns:
|
||||||
@@ -116,10 +110,14 @@ svc_t *svc_iterator(int first)
|
|||||||
if (first)
|
if (first)
|
||||||
i = 0;
|
i = 0;
|
||||||
|
|
||||||
if (i >= svc_counter)
|
while (i < MAX_NUM_SVC) {
|
||||||
return NULL;
|
svc_t *svc = &services[i++];
|
||||||
|
|
||||||
return &services[i++];
|
if (svc->type != SVC_TYPE_FREE)
|
||||||
|
return svc;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -168,7 +166,7 @@ svc_t *svc_find_inetd(char *path, char *service, char *proto, char *port)
|
|||||||
svc_t *svc;
|
svc_t *svc;
|
||||||
|
|
||||||
for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) {
|
for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) {
|
||||||
if (svc->type != SVC_CMD_INETD)
|
if (svc->type != SVC_TYPE_INETD)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (strncmp(path, svc->cmd, strlen(svc->cmd)))
|
if (strncmp(path, svc->cmd, strlen(svc->cmd)))
|
||||||
@@ -184,6 +182,25 @@ svc_t *svc_find_inetd(char *path, char *service, char *proto, char *port)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* svc_mark_dynamic - Mark dynamically loaded services for deletion.
|
||||||
|
*
|
||||||
|
* This function traverses the list of known services, marking all that
|
||||||
|
* have been loaded from /etc/finit.d/ for deletion. If a .conf file
|
||||||
|
* has been removed svc_cleanup() will stop and delete the service.
|
||||||
|
*
|
||||||
|
* This function is called from sighup_cb().
|
||||||
|
*/
|
||||||
|
void svc_mark_dynamic(void)
|
||||||
|
{
|
||||||
|
svc_t *svc;
|
||||||
|
|
||||||
|
for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) {
|
||||||
|
if (svc->mtime)
|
||||||
|
svc->dirty = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* svc_bootstrap - Start bootstrap services and tasks
|
* svc_bootstrap - Start bootstrap services and tasks
|
||||||
*
|
*
|
||||||
@@ -199,7 +216,7 @@ void svc_bootstrap(void)
|
|||||||
svc_cmd_t cmd;
|
svc_cmd_t cmd;
|
||||||
|
|
||||||
/* Inetd services cannot be part of bootstrap currently. */
|
/* Inetd services cannot be part of bootstrap currently. */
|
||||||
if (svc->type == SVC_CMD_INETD)
|
if (svc->type == SVC_TYPE_INETD)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
cmd = svc_enabled(svc, 0, NULL);
|
cmd = svc_enabled(svc, 0, NULL);
|
||||||
@@ -229,6 +246,22 @@ static void utmp_save(int pre, int now)
|
|||||||
endutent();
|
endutent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Singing and dancing ... */
|
||||||
|
static void svc_dance(svc_t *svc)
|
||||||
|
{
|
||||||
|
svc_cmd_t cmd = svc_enabled(svc, 0, NULL);
|
||||||
|
|
||||||
|
if (svc->pid) {
|
||||||
|
if (cmd == SVC_STOP)
|
||||||
|
svc_stop(svc);
|
||||||
|
else if (cmd == SVC_RELOAD)
|
||||||
|
svc_reload(svc);
|
||||||
|
} else {
|
||||||
|
if (cmd == SVC_START)
|
||||||
|
svc_start(svc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* svc_runlevel - Change to a new runlevel
|
* svc_runlevel - Change to a new runlevel
|
||||||
* @newlevel: New runlevel to activate
|
* @newlevel: New runlevel to activate
|
||||||
@@ -253,11 +286,9 @@ void svc_runlevel(int newlevel)
|
|||||||
_d("Setting new runlevel --> %d <-- previous %d", runlevel, prevlevel);
|
_d("Setting new runlevel --> %d <-- previous %d", runlevel, prevlevel);
|
||||||
|
|
||||||
for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) {
|
for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) {
|
||||||
svc_cmd_t cmd;
|
|
||||||
|
|
||||||
/* Inetd services have slightly different semantics */
|
/* Inetd services have slightly different semantics */
|
||||||
#ifndef INETD_DISABLED
|
#ifndef INETD_DISABLED
|
||||||
if (svc->type == SVC_CMD_INETD) {
|
if (svc->type == SVC_TYPE_INETD) {
|
||||||
if (!ISSET(svc->runlevels, runlevel))
|
if (!ISSET(svc->runlevels, runlevel))
|
||||||
inetd_stop(&svc->inetd);
|
inetd_stop(&svc->inetd);
|
||||||
else
|
else
|
||||||
@@ -268,16 +299,7 @@ void svc_runlevel(int newlevel)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* All other services consult their callback here */
|
/* All other services consult their callback here */
|
||||||
cmd = svc_enabled(svc, 0, NULL);
|
svc_dance(svc);
|
||||||
if (svc->pid) {
|
|
||||||
if (cmd == SVC_STOP)
|
|
||||||
svc_stop(svc);
|
|
||||||
else if (cmd == SVC_RELOAD)
|
|
||||||
svc_reload(svc);
|
|
||||||
} else {
|
|
||||||
if (cmd == SVC_START)
|
|
||||||
svc_start(svc);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (0 == runlevel) {
|
if (0 == runlevel) {
|
||||||
@@ -300,8 +322,9 @@ void svc_runlevel(int newlevel)
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* svc_register - Register service, task or run commands
|
* svc_register - Register service, task or run commands
|
||||||
* @type: %SVC_CMD_SERVICE(0), %SVC_CMD_TASK(1), %SVC_CMD_RUN(2)
|
* @type: %SVC_TYPE_SERVICE(0), %SVC_TYPE_TASK(1), %SVC_TYPE_RUN(2)
|
||||||
* @line: A complete command line with -- separated description text
|
* @line: A complete command line with -- separated description text
|
||||||
|
* @mtime: The modification time if service is loaded from /etc/finit.d
|
||||||
* @username: Optional username to run service as, or %NULL to run as root
|
* @username: Optional username to run service as, or %NULL to run as root
|
||||||
*
|
*
|
||||||
* This function is used to register commands to be run on different
|
* This function is used to register commands to be run on different
|
||||||
@@ -319,7 +342,7 @@ void svc_runlevel(int newlevel)
|
|||||||
* "inetd tcp/ssh nowait [2345] @root:root /usr/sbin/sshd -i -- Description"
|
* "inetd tcp/ssh nowait [2345] @root:root /usr/sbin/sshd -i -- Description"
|
||||||
*
|
*
|
||||||
* If the username is left out the command is started as root.
|
* If the username is left out the command is started as root.
|
||||||
* Inetd services, launched on demand (SVC_CMD_INETD)
|
* Inetd services, launched on demand (SVC_TYPE_INETD)
|
||||||
* The [] brackets are there to denote the allowed runlevels. Allowed
|
* The [] brackets are there to denote the allowed runlevels. Allowed
|
||||||
* runlevels mimic that of SysV init with the addition of the 'S'
|
* runlevels mimic that of SysV init with the addition of the 'S'
|
||||||
* runlevel, which is only run once at startup. It can be seen as the
|
* runlevel, which is only run once at startup. It can be seen as the
|
||||||
@@ -329,7 +352,7 @@ void svc_runlevel(int newlevel)
|
|||||||
* Returns:
|
* Returns:
|
||||||
* POSIX OK(0) on success, or non-zero errno exit status on failure.
|
* POSIX OK(0) on success, or non-zero errno exit status on failure.
|
||||||
*/
|
*/
|
||||||
int svc_register(int type, char *line, char *username)
|
int svc_register(int type, char *line, time_t mtime, char *username)
|
||||||
{
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
#ifndef INETD_DISABLED
|
#ifndef INETD_DISABLED
|
||||||
@@ -396,7 +419,7 @@ int svc_register(int type, char *line, char *username)
|
|||||||
|
|
||||||
#ifndef INETD_DISABLED
|
#ifndef INETD_DISABLED
|
||||||
/* Find plugin that provides a callback for this inetd service */
|
/* Find plugin that provides a callback for this inetd service */
|
||||||
if (type == SVC_CMD_INETD && !strncasecmp(cmd, "internal", 8)) {
|
if (type == SVC_TYPE_INETD && !strncasecmp(cmd, "internal", 8)) {
|
||||||
plugin = plugin_find(service);
|
plugin = plugin_find(service);
|
||||||
if (!plugin || !plugin->inetd.cmd) {
|
if (!plugin || !plugin->inetd.cmd) {
|
||||||
_e("Inetd service %s has no internal plugin, skipping.", service);
|
_e("Inetd service %s has no internal plugin, skipping.", service);
|
||||||
@@ -410,13 +433,18 @@ int svc_register(int type, char *line, char *username)
|
|||||||
return inetd_allow(&svc->inetd, iface);
|
return inetd_allow(&svc->inetd, iface);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
svc = svc_new();
|
svc = svc_find(cmd);
|
||||||
if (!svc) {
|
if (!svc) {
|
||||||
_e("Out of memory, cannot register service %s", cmd);
|
svc = svc_new();
|
||||||
return errno = ENOMEM;
|
if (!svc) {
|
||||||
|
_e("Out of memory, cannot register service %s", cmd);
|
||||||
|
return errno = ENOMEM;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
if (svc->mtime != mtime)
|
||||||
svc->type = type;
|
svc->dirty = 1;
|
||||||
|
svc->mtime = mtime;
|
||||||
|
svc->type = type;
|
||||||
|
|
||||||
if (desc)
|
if (desc)
|
||||||
strlcpy(svc->desc, desc + 3, sizeof(svc->desc));
|
strlcpy(svc->desc, desc + 3, sizeof(svc->desc));
|
||||||
@@ -432,7 +460,7 @@ int svc_register(int type, char *line, char *username)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifndef INETD_DISABLED
|
#ifndef INETD_DISABLED
|
||||||
if (svc->type == SVC_CMD_INETD) {
|
if (svc->type == SVC_TYPE_INETD) {
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
result = inetd_new(&svc->inetd, service, proto, forking);
|
result = inetd_new(&svc->inetd, service, proto, forking);
|
||||||
@@ -552,7 +580,7 @@ static void restart_any_lost_procs(void)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Only restart lost daemons, not task/run/inetd services */
|
/* Only restart lost daemons, not task/run/inetd services */
|
||||||
if (SVC_CMD_SERVICE != svc->type) {
|
if (SVC_TYPE_SERVICE != svc->type) {
|
||||||
svc->pid = 0;
|
svc->pid = 0;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -592,7 +620,7 @@ void svc_monitor(pid_t lost)
|
|||||||
if (lost != svc->pid)
|
if (lost != svc->pid)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (SVC_CMD_SERVICE != svc->type) {
|
if (SVC_TYPE_SERVICE != svc->type) {
|
||||||
svc->pid = 0;
|
svc->pid = 0;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -648,7 +676,7 @@ int svc_start(svc_t *svc)
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
#ifndef INETD_DISABLED
|
#ifndef INETD_DISABLED
|
||||||
if (SVC_CMD_INETD == svc->type) {
|
if (SVC_TYPE_INETD == svc->type) {
|
||||||
char ifname[IF_NAMESIZE] = "UNKNOWN";
|
char ifname[IF_NAMESIZE] = "UNKNOWN";
|
||||||
|
|
||||||
sd = svc->inetd.watcher.fd;
|
sd = svc->inetd.watcher.fd;
|
||||||
@@ -682,7 +710,7 @@ int svc_start(svc_t *svc)
|
|||||||
FLOG_INFO("Starting inetd service %s for requst from iface %s ...", svc->inetd.name, ifname);
|
FLOG_INFO("Starting inetd service %s for requst from iface %s ...", svc->inetd.name, ifname);
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
if (SVC_CMD_SERVICE != svc->type)
|
if (SVC_TYPE_SERVICE != svc->type)
|
||||||
print_desc("", svc->desc);
|
print_desc("", svc->desc);
|
||||||
else if (!respawn)
|
else if (!respawn)
|
||||||
print_desc("Starting ", svc->desc);
|
print_desc("Starting ", svc->desc);
|
||||||
@@ -723,7 +751,7 @@ int svc_start(svc_t *svc)
|
|||||||
args[i] = NULL;
|
args[i] = NULL;
|
||||||
|
|
||||||
/* Redirect inetd socket to stdin for service */
|
/* Redirect inetd socket to stdin for service */
|
||||||
if (SVC_CMD_INETD == svc->type) {
|
if (SVC_TYPE_INETD == svc->type) {
|
||||||
/* sd set previously */
|
/* sd set previously */
|
||||||
dup2(sd, STDIN_FILENO);
|
dup2(sd, STDIN_FILENO);
|
||||||
close(sd);
|
close(sd);
|
||||||
@@ -755,7 +783,7 @@ int svc_start(svc_t *svc)
|
|||||||
else
|
else
|
||||||
status = execv(svc->cmd, args); /* XXX: Maybe use execve() to be able to launch scripts? */
|
status = execv(svc->cmd, args); /* XXX: Maybe use execve() to be able to launch scripts? */
|
||||||
|
|
||||||
if (SVC_CMD_INETD == svc->type) {
|
if (SVC_TYPE_INETD == svc->type) {
|
||||||
if (svc->inetd.type == SOCK_STREAM) {
|
if (svc->inetd.type == SOCK_STREAM) {
|
||||||
close(STDIN_FILENO);
|
close(STDIN_FILENO);
|
||||||
close(STDOUT_FILENO);
|
close(STDOUT_FILENO);
|
||||||
@@ -767,11 +795,11 @@ int svc_start(svc_t *svc)
|
|||||||
}
|
}
|
||||||
svc->pid = pid;
|
svc->pid = pid;
|
||||||
|
|
||||||
if (SVC_CMD_INETD == svc->type) {
|
if (SVC_TYPE_INETD == svc->type) {
|
||||||
if (svc->inetd.type == SOCK_STREAM)
|
if (svc->inetd.type == SOCK_STREAM)
|
||||||
close(sd);
|
close(sd);
|
||||||
}
|
}
|
||||||
else if (SVC_CMD_RUN == svc->type)
|
else if (SVC_TYPE_RUN == svc->type)
|
||||||
print_result(WEXITSTATUS(complete(svc->cmd, pid)));
|
print_result(WEXITSTATUS(complete(svc->cmd, pid)));
|
||||||
else if (!respawn)
|
else if (!respawn)
|
||||||
print_result(svc->pid > 1 ? 0 : 1);
|
print_result(svc->pid > 1 ? 0 : 1);
|
||||||
@@ -805,7 +833,7 @@ int svc_stop(svc_t *svc)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SVC_CMD_SERVICE != svc->type)
|
if (SVC_TYPE_SERVICE != svc->type)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (runlevel != 1)
|
if (runlevel != 1)
|
||||||
@@ -820,6 +848,16 @@ int svc_stop(svc_t *svc)
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* svc_reload - Send SIGHUP to a service
|
||||||
|
* @svc: Service to reload
|
||||||
|
*
|
||||||
|
* This function does some basic checks of the runtime state of Finit
|
||||||
|
* and a sanity check of the @svc before sending %SIGHUP.
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* POSIX OK(0) or non-zero on error.
|
||||||
|
*/
|
||||||
int svc_reload(svc_t *svc)
|
int svc_reload(svc_t *svc)
|
||||||
{
|
{
|
||||||
/* Ignore if finit is SIGSTOP'ed */
|
/* Ignore if finit is SIGSTOP'ed */
|
||||||
@@ -841,6 +879,43 @@ int svc_reload(svc_t *svc)
|
|||||||
return kill(svc->pid, SIGHUP);
|
return kill(svc->pid, SIGHUP);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* svc_reload_dynamic - Reload modifued dynamic services
|
||||||
|
*
|
||||||
|
* This function is called when Finit has recieved SIGHUP to reload
|
||||||
|
* .conf files in /etc/finit.d. It is responsible for starting,
|
||||||
|
* stopping and reloading (forwarding SIGHUP) to processes affected.
|
||||||
|
*/
|
||||||
|
void svc_reload_dynamic(void)
|
||||||
|
{
|
||||||
|
svc_t *svc;
|
||||||
|
|
||||||
|
for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) {
|
||||||
|
if (svc->mtime && svc->dirty > 0) {
|
||||||
|
svc_dance(svc);
|
||||||
|
svc->dirty = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* svc_cleanup - Stop and cleanup stale services removed from /etc/finit.d
|
||||||
|
*
|
||||||
|
* This function traverses the list of known services to stop and clean
|
||||||
|
* up all non-existing services previously marked by svc_mark_dynamic().
|
||||||
|
*/
|
||||||
|
void svc_cleanup(void)
|
||||||
|
{
|
||||||
|
svc_t *svc;
|
||||||
|
|
||||||
|
for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) {
|
||||||
|
if (svc->mtime && svc->dirty == -1) {
|
||||||
|
svc_stop(svc);
|
||||||
|
svc_del(svc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Local Variables:
|
* Local Variables:
|
||||||
* version-control: t
|
* version-control: t
|
||||||
|
|||||||
@@ -42,10 +42,11 @@ typedef enum {
|
|||||||
} svc_cmd_t;
|
} svc_cmd_t;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
SVC_CMD_SERVICE = 0, /* Monitored, will be respawned */
|
SVC_TYPE_FREE = 0, /* Free to allocate */
|
||||||
SVC_CMD_TASK, /* One-shot, runs in parallell */
|
SVC_TYPE_SERVICE , /* Monitored, will be respawned */
|
||||||
SVC_CMD_RUN, /* Like task, but wait for completion */
|
SVC_TYPE_TASK, /* One-shot, runs in parallell */
|
||||||
SVC_CMD_INETD /* Classic inetd service */
|
SVC_TYPE_RUN, /* Like task, but wait for completion */
|
||||||
|
SVC_TYPE_INETD /* Classic inetd service */
|
||||||
} svc_type_t;
|
} svc_type_t;
|
||||||
|
|
||||||
#define FINIT_SHM_ID 0x494E4954 /* "INIT", see ascii(7) */
|
#define FINIT_SHM_ID 0x494E4954 /* "INIT", see ascii(7) */
|
||||||
@@ -62,7 +63,9 @@ typedef enum {
|
|||||||
typedef struct svc {
|
typedef struct svc {
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
svc_type_t type;
|
svc_type_t type;
|
||||||
int reload;
|
time_t mtime; /* Modification time for .conf from /etc/finit.d/ */
|
||||||
|
int dirty; /* Set if old mtime != new mtime => reloaded,
|
||||||
|
* or -1 when marked for removal */
|
||||||
int runlevels;
|
int runlevels;
|
||||||
|
|
||||||
/* Incremented for each restart by service monitor. */
|
/* Incremented for each restart by service monitor. */
|
||||||
@@ -80,7 +83,7 @@ typedef struct svc {
|
|||||||
char args[MAX_NUM_SVC_ARGS][MAX_ARG_LEN];
|
char args[MAX_NUM_SVC_ARGS][MAX_ARG_LEN];
|
||||||
char desc[MAX_STR_LEN];
|
char desc[MAX_STR_LEN];
|
||||||
|
|
||||||
/* For external plugins. If @cb is set a plugin is loaded.
|
/* For external plugins. If @cb is set, a plugin is loaded.
|
||||||
* @dynamic: Set by plugins that want dynamic events.
|
* @dynamic: Set by plugins that want dynamic events.
|
||||||
* @dynamic_stop: Set by plugins that allow dyn. events to stop it as well.
|
* @dynamic_stop: Set by plugins that allow dyn. events to stop it as well.
|
||||||
* @private: Can be used freely by plugin, e.g., to store "states".
|
* @private: Can be used freely by plugin, e.g., to store "states".
|
||||||
@@ -114,15 +117,18 @@ svc_t *svc_find (char *path);
|
|||||||
svc_t *svc_find_by_pid (pid_t pid);
|
svc_t *svc_find_by_pid (pid_t pid);
|
||||||
svc_t *svc_find_inetd (char *path, char *service, char *proto, char *port);
|
svc_t *svc_find_inetd (char *path, char *service, char *proto, char *port);
|
||||||
svc_t *svc_iterator (int first);
|
svc_t *svc_iterator (int first);
|
||||||
|
void svc_mark_dynamic (void);
|
||||||
void svc_runlevel (int newlevel);
|
void svc_runlevel (int newlevel);
|
||||||
|
|
||||||
int svc_register (int type, char *line, char *username);
|
int svc_register (int type, char *line, time_t mtime, char *username);
|
||||||
int svc_id_by_name (char *name);
|
int svc_id_by_name (char *name);
|
||||||
svc_cmd_t svc_enabled (svc_t *svc, int event, void *arg);
|
svc_cmd_t svc_enabled (svc_t *svc, int event, void *arg);
|
||||||
int svc_start (svc_t *svc);
|
int svc_start (svc_t *svc);
|
||||||
int svc_start_by_name (char *name);
|
int svc_start_by_name (char *name);
|
||||||
int svc_stop (svc_t *svc);
|
int svc_stop (svc_t *svc);
|
||||||
int svc_reload (svc_t *svc);
|
int svc_reload (svc_t *svc);
|
||||||
|
void svc_reload_dynamic(void);
|
||||||
|
void svc_cleanup (void);
|
||||||
|
|
||||||
#endif /* FINIT_SVC_H_ */
|
#endif /* FINIT_SVC_H_ */
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user