mirror of
https://github.com/troglobit/finit.git
synced 2026-10-13 10:14:47 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fca5ce57ea | ||
|
|
53aa195ad5 | ||
|
|
e60211168e | ||
|
|
dc3ee9e467 | ||
|
|
6918f3b711 | ||
|
|
66020f48ea | ||
|
|
47b0d4cccf | ||
|
|
92c2efa655 | ||
|
|
b69aa8a8bd | ||
|
|
ca90bbfb04 | ||
|
|
0b5c555c7f | ||
|
|
6443995fc9 | ||
|
|
180faf8a40 | ||
|
|
0ebdd32f6b | ||
|
|
60bf858302 | ||
|
|
7c86b40190 |
+22
-1
@@ -4,6 +4,26 @@ Change Log
|
|||||||
All relevant changes are documented in this file.
|
All relevant changes are documented in this file.
|
||||||
|
|
||||||
|
|
||||||
|
[4.6][] - 2023-11-13
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
### Changes
|
||||||
|
- Add support for service `notify:pid` and `readiness none` global
|
||||||
|
option to change how Finit expects readiness notification, issue #386
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
- Fix #383: dbus and runparts regression in Finit v4.5. The configure
|
||||||
|
script must expand `FINIT_RUNPATH_` before defining it in `config.h`
|
||||||
|
- Fix #384: service environment variables drop everything but the first
|
||||||
|
argument, e.g., `VAR="foo bar qux"` drops everything but `foo`
|
||||||
|
- Fix #385: internal conditions, e.g., `<int/bootstrap>` turn into flux
|
||||||
|
when leaving bootstrap, causing depending services to stop
|
||||||
|
- Fix #387: global environment variables declared with `set VAR=NAME` do
|
||||||
|
not drop leading `set `, causing `'set VAR'='NAME'` in env.
|
||||||
|
- Sanity check environment variables, for services and globally. Ensure
|
||||||
|
the variable name (key) does not contain spaces, or a leading `set `
|
||||||
|
|
||||||
|
|
||||||
[4.5][] - 2023-10-30
|
[4.5][] - 2023-10-30
|
||||||
--------------------
|
--------------------
|
||||||
|
|
||||||
@@ -1613,7 +1633,8 @@ Major bug fix release.
|
|||||||
|
|
||||||
* Initial release
|
* Initial release
|
||||||
|
|
||||||
[UNRELEASED]: https://github.com/troglobit/finit/compare/4.5...HEAD
|
[UNRELEASED]: https://github.com/troglobit/finit/compare/4.6...HEAD
|
||||||
|
[4.6]: https://github.com/troglobit/finit/compare/4.5...4.6
|
||||||
[4.5]: https://github.com/troglobit/finit/compare/4.4...4.5
|
[4.5]: https://github.com/troglobit/finit/compare/4.4...4.5
|
||||||
[4.4]: https://github.com/troglobit/finit/compare/4.3...4.4
|
[4.4]: https://github.com/troglobit/finit/compare/4.3...4.4
|
||||||
[4.3]: https://github.com/troglobit/finit/compare/4.2...4.3
|
[4.3]: https://github.com/troglobit/finit/compare/4.2...4.3
|
||||||
|
|||||||
+3
-2
@@ -1,4 +1,4 @@
|
|||||||
AC_INIT([Finit], [4.5], [https://github.com/troglobit/finit/issues],
|
AC_INIT([Finit], [4.6], [https://github.com/troglobit/finit/issues],
|
||||||
[finit], [https://troglobit.com/projects/finit/])
|
[finit], [https://troglobit.com/projects/finit/])
|
||||||
AC_CONFIG_AUX_DIR(aux)
|
AC_CONFIG_AUX_DIR(aux)
|
||||||
AM_INIT_AUTOMAKE([1.11 foreign dist-xz subdir-objects])
|
AM_INIT_AUTOMAKE([1.11 foreign dist-xz subdir-objects])
|
||||||
@@ -314,7 +314,8 @@ pkglibdir=$libdir/finit
|
|||||||
AC_SUBST(pkglibexecdir)
|
AC_SUBST(pkglibexecdir)
|
||||||
AC_EXPAND_DIR(pkglibexecdir, "$libexecdir/finit")
|
AC_EXPAND_DIR(pkglibexecdir, "$libexecdir/finit")
|
||||||
AC_DEFINE_UNQUOTED(FINIT_EXECPATH_, "$pkglibexecdir", [Finit libexec path])
|
AC_DEFINE_UNQUOTED(FINIT_EXECPATH_, "$pkglibexecdir", [Finit libexec path])
|
||||||
AC_DEFINE_UNQUOTED(FINIT_RUNPATH_, "$runstatedir/finit/system", [Finit runtime dynamic system services])
|
AC_EXPAND_DIR(finit_runpath, "$runstatedir/finit/system")
|
||||||
|
AC_DEFINE_UNQUOTED(FINIT_RUNPATH_, "$finit_runpath", [Finit runtime dynamic system services])
|
||||||
|
|
||||||
AC_EXPAND_DIR(plugin_path, "$pkglibdir/plugins")
|
AC_EXPAND_DIR(plugin_path, "$pkglibdir/plugins")
|
||||||
AC_SUBST(plugin_path)
|
AC_SUBST(plugin_path)
|
||||||
|
|||||||
+19
-5
@@ -356,17 +356,31 @@ most notably systemd and s6, other methods for signaling "readiness"
|
|||||||
arrived and daemons were adapted to these new schemes to a larger
|
arrived and daemons were adapted to these new schemes to a larger
|
||||||
extent.
|
extent.
|
||||||
|
|
||||||
As of Finit v4.4 partial support for systemd and s6 is available. The
|
As of Finit v4.4 partial support for systemd and s6 style readiness
|
||||||
native PID file mode of operation is still default, the other's can be
|
notification is available, and the native PID file mode of operation is,
|
||||||
defined per service, like this:
|
as of Finit v4.6 optional, by default it is still enabled, but this can
|
||||||
|
be changed in `finit.conf`:
|
||||||
|
|
||||||
|
readiness none
|
||||||
|
|
||||||
|
This will be made the default in Finit 5.0. In this mode of operation,
|
||||||
|
every service needs to explicitly declare their readiness notification,
|
||||||
|
like this:
|
||||||
|
|
||||||
|
service notify:pid watchdogd
|
||||||
service notify:systemd foo
|
service notify:systemd foo
|
||||||
service notify:s6 bar
|
service notify:s6 bar
|
||||||
|
service notify:none qux
|
||||||
|
|
||||||
|
The `notify:none` syntax is for completeness in systems which run in
|
||||||
|
`readiness pid` mode (default). Services declared with `notify:none`
|
||||||
|
will assert ready condition as soon as Finit has started them, e.g.,
|
||||||
|
`service/qux/ready`.
|
||||||
|
|
||||||
To synchronize two services the following condition can be used:
|
To synchronize two services the following condition can be used:
|
||||||
|
|
||||||
service notify:systemd A
|
service notify:pid watchdogd
|
||||||
service <service/A/ready> B
|
service <service/watchdogd/ready> stress-ng --cpu 8
|
||||||
|
|
||||||
For details on the syntax and options, see below.
|
For details on the syntax and options, see below.
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -150,11 +150,11 @@ static void setup(void *arg)
|
|||||||
* Note: dbus drops privs after starting up.
|
* Note: dbus drops privs after starting up.
|
||||||
*/
|
*/
|
||||||
if (pidfn) {
|
if (pidfn) {
|
||||||
snprintf(line, sizeof(line), "[S123456789] cgroup.system name:dbus pid:!%s %s %s -- %s",
|
snprintf(line, sizeof(line), "[S123456789] cgroup.system notify:none name:dbus pid:!%s %s %s -- %s",
|
||||||
pidfn, cmd, DBUS_ARGS, DBUS_DESC);
|
pidfn, cmd, DBUS_ARGS, DBUS_DESC);
|
||||||
free(pidfn);
|
free(pidfn);
|
||||||
} else
|
} else
|
||||||
snprintf(line, sizeof(line), "[S123456789] cgroup.system name:dbus %s %s -- %s",
|
snprintf(line, sizeof(line), "[S123456789] cgroup.system notify:none name:dbus %s %s -- %s",
|
||||||
cmd, DBUS_ARGS, DBUS_DESC);
|
cmd, DBUS_ARGS, DBUS_DESC);
|
||||||
|
|
||||||
conf_save_service(SVC_TYPE_SERVICE, line, "dbus.conf");
|
conf_save_service(SVC_TYPE_SERVICE, line, "dbus.conf");
|
||||||
|
|||||||
+7
-6
@@ -79,7 +79,7 @@ static void pidfile_update_conds(char *dir, char *name, uint32_t mask)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
dbg("Found svc %s for %s with pid %d", svc->name, fn, svc->pid);
|
dbg("Found svc %s for %s with pid %d", svc_ident(svc, NULL, 0), fn, svc->pid);
|
||||||
mkcond(svc, cond, sizeof(cond));
|
mkcond(svc, cond, sizeof(cond));
|
||||||
|
|
||||||
if (mask & (IN_CLOSE_WRITE | IN_ATTRIB | IN_MODIFY | IN_MOVED_TO)) {
|
if (mask & (IN_CLOSE_WRITE | IN_ATTRIB | IN_MODIFY | IN_MOVED_TO)) {
|
||||||
@@ -88,7 +88,7 @@ static void pidfile_update_conds(char *dir, char *name, uint32_t mask)
|
|||||||
* systemd style services rely on their respective
|
* systemd style services rely on their respective
|
||||||
* readiness notification. Issue #343
|
* readiness notification. Issue #343
|
||||||
*/
|
*/
|
||||||
if (!svc->notify)
|
if (svc->notify == SVC_NOTIFY_PID)
|
||||||
svc_started(svc);
|
svc_started(svc);
|
||||||
|
|
||||||
if (!svc_has_pidfile(svc)) {
|
if (!svc_has_pidfile(svc)) {
|
||||||
@@ -120,12 +120,13 @@ static void pidfile_update_conds(char *dir, char *name, uint32_t mask)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cond_set(cond);
|
if (svc->notify == SVC_NOTIFY_PID)
|
||||||
if (!svc->notify)
|
cond_set(cond);
|
||||||
|
if (svc->notify == SVC_NOTIFY_PID || svc->notify == SVC_NOTIFY_NONE)
|
||||||
service_ready(svc);
|
service_ready(svc);
|
||||||
} else if (mask & IN_DELETE) {
|
} else if (mask & IN_DELETE) {
|
||||||
cond_clear(cond);
|
cond_clear(cond);
|
||||||
if (!svc->notify)
|
if (svc->notify == SVC_NOTIFY_PID)
|
||||||
service_ready(svc);
|
service_ready(svc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -240,7 +241,7 @@ static void pidfile_reconf(void *arg)
|
|||||||
if (svc_is_changed(svc) || svc_is_starting(svc))
|
if (svc_is_changed(svc) || svc_is_starting(svc))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!svc->notify)
|
if (svc->notify == SVC_NOTIFY_PID)
|
||||||
service_ready(svc);
|
service_ready(svc);
|
||||||
|
|
||||||
mkcond(svc, cond, sizeof(cond));
|
mkcond(svc, cond, sizeof(cond));
|
||||||
|
|||||||
+34
-4
@@ -545,6 +545,23 @@ static void parse_env(char *line)
|
|||||||
*end-- = 0;
|
*end-- = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* strip any leading 'set ' */
|
||||||
|
end = key;
|
||||||
|
if (!strncmp(key, "set", 3))
|
||||||
|
end += 3;
|
||||||
|
|
||||||
|
/* check key, no spaces allowed */
|
||||||
|
while (*end && isspace(*end))
|
||||||
|
end++;
|
||||||
|
key = end;
|
||||||
|
while (*end && !isspace(*end))
|
||||||
|
end++;
|
||||||
|
if (*end != 0) {
|
||||||
|
warnx("'%s=%s': not a valid identifier", key, val);
|
||||||
|
return; /* invalid key */
|
||||||
|
}
|
||||||
|
|
||||||
|
dbg("Global env '%s'='%s'", key, val);
|
||||||
setenv(key, val, 1);
|
setenv(key, val, 1);
|
||||||
|
|
||||||
node = malloc(sizeof(*node));
|
node = malloc(sizeof(*node));
|
||||||
@@ -958,6 +975,18 @@ static int parse_static(char *line, int is_rcsd)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Before Finit 5 the default readiness notification is PID.
|
||||||
|
* This default can be changed by setting 'readiness none' in
|
||||||
|
* the file /etc/finit.conf, only read once at bootstrap.
|
||||||
|
*/
|
||||||
|
if (BOOTSTRAP && MATCH_CMD(line, "readiness ", x)) {
|
||||||
|
char *token = strip_line(x);
|
||||||
|
|
||||||
|
if (!strcmp(token, "none"))
|
||||||
|
readiness = SVC_NOTIFY_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
if (MATCH_CMD(line, "reboot-delay ", x)) {
|
if (MATCH_CMD(line, "reboot-delay ", x)) {
|
||||||
syncsec = strtonum(strip_line(x), 0, 60, NULL);
|
syncsec = strtonum(strip_line(x), 0, 60, NULL);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -1393,7 +1422,8 @@ static int conf_change_act(char *dir, char *name, uint32_t mask)
|
|||||||
struct conf_change *node;
|
struct conf_change *node;
|
||||||
char *rp = NULL;
|
char *rp = NULL;
|
||||||
|
|
||||||
if (name[0])
|
/* Check for actual printable characters, sometimes STX */
|
||||||
|
if (name[0] && name[0] >= ' ')
|
||||||
paste(fn, sizeof(fn), dir, name);
|
paste(fn, sizeof(fn), dir, name);
|
||||||
else
|
else
|
||||||
strlcpy(fn, dir, sizeof(fn));
|
strlcpy(fn, dir, sizeof(fn));
|
||||||
@@ -1579,7 +1609,7 @@ int conf_init(uev_ctx_t *ctx)
|
|||||||
*/
|
*/
|
||||||
#ifdef WDT_DEVNODE
|
#ifdef WDT_DEVNODE
|
||||||
if (whichp(FINIT_EXECPATH_ "/watchdogd") && fexist(WDT_DEVNODE)) {
|
if (whichp(FINIT_EXECPATH_ "/watchdogd") && fexist(WDT_DEVNODE)) {
|
||||||
conf_save_service(SVC_TYPE_SERVICE, "[S0123456789] cgroup.init name:watchdog :finit "
|
conf_save_service(SVC_TYPE_SERVICE, "[S0123456789] cgroup.init notify:none name:watchdog :finit "
|
||||||
FINIT_EXECPATH_ "/watchdogd -- Finit watchdog daemon", "watchdogd.conf");
|
FINIT_EXECPATH_ "/watchdogd -- Finit watchdog daemon", "watchdogd.conf");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -1587,7 +1617,7 @@ int conf_init(uev_ctx_t *ctx)
|
|||||||
* Start kernel event daemon as soon as possible, if enabled
|
* Start kernel event daemon as soon as possible, if enabled
|
||||||
*/
|
*/
|
||||||
if (whichp(FINIT_EXECPATH_ "/keventd"))
|
if (whichp(FINIT_EXECPATH_ "/keventd"))
|
||||||
conf_save_service(SVC_TYPE_SERVICE, "[S0123456789] cgroup.init "
|
conf_save_service(SVC_TYPE_SERVICE, "[S0123456789] cgroup.init notify:none "
|
||||||
FINIT_EXECPATH_ "/keventd -- Finit kernel event daemon", "keventd.conf");
|
FINIT_EXECPATH_ "/keventd -- Finit kernel event daemon", "keventd.conf");
|
||||||
|
|
||||||
dbg("Allow plugins to register early runlevel 1 run/task/services ...");
|
dbg("Allow plugins to register early runlevel 1 run/task/services ...");
|
||||||
@@ -1621,7 +1651,7 @@ int conf_init(uev_ctx_t *ctx)
|
|||||||
if (runparts_sysv)
|
if (runparts_sysv)
|
||||||
strlcat(args, "-s ", sizeof(args));
|
strlcat(args, "-s ", sizeof(args));
|
||||||
|
|
||||||
snprintf(conf, sizeof(conf), "[S] <int/bootstrap> log:console %s %s %s"
|
snprintf(conf, sizeof(conf), "[S] <int/bootstrap> notify:none log:console %s %s %s"
|
||||||
" -- Calling runparts %s in the background",
|
" -- Calling runparts %s in the background",
|
||||||
_PATH_RUNPARTS, args, runparts, runparts);
|
_PATH_RUNPARTS, args, runparts, runparts);
|
||||||
conf_save_service(SVC_TYPE_TASK, conf, "runparts.conf");
|
conf_save_service(SVC_TYPE_TASK, conf, "runparts.conf");
|
||||||
|
|||||||
+2
-1
@@ -69,6 +69,7 @@ int single = 0; /* single user mode from kernel cmdline */
|
|||||||
int bootstrap = 1; /* set while bootrapping (for TTYs) */
|
int bootstrap = 1; /* set while bootrapping (for TTYs) */
|
||||||
int kerndebug = 0; /* set if /proc/sys/kernel/printk > 7 */
|
int kerndebug = 0; /* set if /proc/sys/kernel/printk > 7 */
|
||||||
int syncsec = 0; /* reboot delay */
|
int syncsec = 0; /* reboot delay */
|
||||||
|
int readiness = SVC_NOTIFY_PID;
|
||||||
char *finit_conf= NULL;
|
char *finit_conf= NULL;
|
||||||
char *finit_rcsd= NULL;
|
char *finit_rcsd= NULL;
|
||||||
char *fstab = NULL;
|
char *fstab = NULL;
|
||||||
@@ -697,7 +698,7 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
/* Some bootstrap tasks may need to know if we're in a container. */
|
/* Some bootstrap tasks may need to know if we're in a container. */
|
||||||
if (in_container())
|
if (in_container())
|
||||||
cond_set("int/container");
|
cond_set_oneshot("int/container");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize .conf system and load static /etc/finit.conf then
|
* Initialize .conf system and load static /etc/finit.conf then
|
||||||
|
|||||||
@@ -121,6 +121,7 @@ extern int single;
|
|||||||
extern int bootstrap;
|
extern int bootstrap;
|
||||||
extern int kerndebug;
|
extern int kerndebug;
|
||||||
extern int syncsec;
|
extern int syncsec;
|
||||||
|
extern int readiness;
|
||||||
extern char *fstab;
|
extern char *fstab;
|
||||||
extern char *sdown;
|
extern char *sdown;
|
||||||
extern char *network;
|
extern char *network;
|
||||||
|
|||||||
+77
-43
@@ -394,11 +394,8 @@ static int redirect(svc_t *svc)
|
|||||||
*/
|
*/
|
||||||
static void source_env(svc_t *svc)
|
static void source_env(svc_t *svc)
|
||||||
{
|
{
|
||||||
char buf[LINE_SIZE];
|
char *buf, *val, *line, *fn;
|
||||||
char *line;
|
|
||||||
size_t len;
|
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
char *fn;
|
|
||||||
|
|
||||||
fn = svc_getenv(svc);
|
fn = svc_getenv(svc);
|
||||||
if (!fn)
|
if (!fn)
|
||||||
@@ -409,12 +406,19 @@ static void source_env(svc_t *svc)
|
|||||||
if (!fp)
|
if (!fp)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
buf = alloca(LINE_SIZE);
|
||||||
|
val = alloca(LINE_SIZE);
|
||||||
|
if (!buf || !val) {
|
||||||
|
warn("Failed allocating temporary env buffer");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
line = buf;
|
line = buf;
|
||||||
len = sizeof(buf);
|
while (fgets(line, LINE_SIZE, fp)) {
|
||||||
while (fgets(line, len, fp)) {
|
|
||||||
char *key = chomp(line);
|
char *key = chomp(line);
|
||||||
wordexp_t we = { 0 };
|
wordexp_t we = { 0 };
|
||||||
char *value, *end;
|
char *value, *end;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
/* skip any leading whitespace */
|
/* skip any leading whitespace */
|
||||||
while (isspace(*key))
|
while (isspace(*key))
|
||||||
@@ -467,9 +471,30 @@ static void source_env(svc_t *svc)
|
|||||||
*end-- = 0;
|
*end-- = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* strip any leading 'set ' */
|
||||||
|
end = key;
|
||||||
|
if (!strncmp(key, "set", 3))
|
||||||
|
end += 3;
|
||||||
|
|
||||||
|
/* check key, no spaces allowed */
|
||||||
|
while (*end && isspace(*end))
|
||||||
|
end++;
|
||||||
|
key = end;
|
||||||
|
while (*end && !isspace(*end))
|
||||||
|
end++;
|
||||||
|
if (*end != 0) {
|
||||||
|
warnx("'%s=%s': not a valid identifier", key, val);
|
||||||
|
continue; /* invalid key */
|
||||||
|
}
|
||||||
|
|
||||||
switch (wordexp(value, &we, 0)) {
|
switch (wordexp(value, &we, 0)) {
|
||||||
case 0:
|
case 0:
|
||||||
setenv(key, we.we_wordv[0], 1);
|
for (i = 0, *val = 0; i < we.we_wordc; i++) {
|
||||||
|
if (i > 0)
|
||||||
|
strlcat(val, " ", LINE_SIZE);
|
||||||
|
strlcat(val, we.we_wordv[i], LINE_SIZE);
|
||||||
|
}
|
||||||
|
setenv(key, val, 1);
|
||||||
wordfree(&we);
|
wordfree(&we);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -692,11 +717,12 @@ static int service_start(svc_t *svc)
|
|||||||
wordexp_t we = { 0 };
|
wordexp_t we = { 0 };
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
if (svc->notify) {
|
if (svc->notify == SVC_NOTIFY_SYSTEMD || svc->notify == SVC_NOTIFY_S6) {
|
||||||
if (client_command(INIT_CMD_NOTIFY_SOCKET)) {
|
if (client_command(INIT_CMD_NOTIFY_SOCKET)) {
|
||||||
err(1, "%s: failed creating notify socket", svc_ident(svc, NULL, 0));
|
err(1, "%s: failed creating notify socket", svc_ident(svc, NULL, 0));
|
||||||
client_disconnect();
|
client_disconnect();
|
||||||
svc->notify = 0; /* does not change parent, restarting may work. */
|
/* does not change parent, restarting may work. */
|
||||||
|
svc->notify = SVC_NOTIFY_NONE;
|
||||||
} else {
|
} else {
|
||||||
char val[20];
|
char val[20];
|
||||||
|
|
||||||
@@ -721,7 +747,7 @@ static int service_start(svc_t *svc)
|
|||||||
if (len == 0)
|
if (len == 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (svc->notify) {
|
if (svc->notify == SVC_NOTIFY_SYSTEMD || svc->notify == SVC_NOTIFY_S6) {
|
||||||
char *ptr = strstr(arg, "%n");
|
char *ptr = strstr(arg, "%n");
|
||||||
|
|
||||||
if (ptr) {
|
if (ptr) {
|
||||||
@@ -898,6 +924,19 @@ static void service_kill(svc_t *svc)
|
|||||||
print(2, NULL);
|
print(2, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Ensure we don't have any notify socket lingering */
|
||||||
|
static void service_notify_stop(svc_t *svc)
|
||||||
|
{
|
||||||
|
if (svc->notify != SVC_NOTIFY_SYSTEMD && svc->notify != SVC_NOTIFY_S6)
|
||||||
|
return;
|
||||||
|
|
||||||
|
uev_io_stop(&svc->notify_watcher);
|
||||||
|
if (svc->notify_watcher.fd > 0) {
|
||||||
|
close(svc->notify_watcher.fd);
|
||||||
|
svc->notify_watcher.fd = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Clean up any lingering state from dead/killed services
|
* Clean up any lingering state from dead/killed services
|
||||||
*/
|
*/
|
||||||
@@ -913,12 +952,7 @@ static void service_cleanup(svc_t *svc)
|
|||||||
logit(LOG_CRIT, "Failed removing service %s pidfile %s",
|
logit(LOG_CRIT, "Failed removing service %s pidfile %s",
|
||||||
svc_ident(svc, NULL, 0), fn);
|
svc_ident(svc, NULL, 0), fn);
|
||||||
|
|
||||||
/* Ensure we don't have any notify socket lingering */
|
service_notify_stop(svc);
|
||||||
if (svc->notify && svc->notify_watcher.fd > 0) {
|
|
||||||
uev_io_stop(&svc->notify_watcher);
|
|
||||||
close(svc->notify_watcher.fd);
|
|
||||||
svc->notify_watcher.fd = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* No longer running, update books. */
|
/* No longer running, update books. */
|
||||||
if (svc_is_tty(svc) && svc->pid > 1)
|
if (svc_is_tty(svc) && svc->pid > 1)
|
||||||
@@ -1179,13 +1213,15 @@ static void parse_log(svc_t *svc, char *arg)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int parse_notify(char *arg)
|
static svc_notify_t parse_notify(char *arg)
|
||||||
{
|
{
|
||||||
if (!strcmp(arg, "systemd"))
|
if (!strcmp(arg, "systemd"))
|
||||||
return 1;
|
return SVC_NOTIFY_SYSTEMD;
|
||||||
if (!strcmp(arg, "s6"))
|
if (!strcmp(arg, "s6"))
|
||||||
return 2;
|
return SVC_NOTIFY_S6;
|
||||||
return 0; /* unsupported/disabled */
|
if (!strcmp(arg, "pid"))
|
||||||
|
return SVC_NOTIFY_PID;
|
||||||
|
return SVC_NOTIFY_NONE; /* unsupported/none */
|
||||||
}
|
}
|
||||||
|
|
||||||
static void parse_env(svc_t *svc, char *env)
|
static void parse_env(svc_t *svc, char *env)
|
||||||
@@ -1750,17 +1786,12 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
|
|||||||
else
|
else
|
||||||
svc->log.enabled = 0;
|
svc->log.enabled = 0;
|
||||||
}
|
}
|
||||||
if (notify) {
|
|
||||||
int type = parse_notify(notify);
|
|
||||||
|
|
||||||
if (type <= 0)
|
if (notify)
|
||||||
goto disable_notify;
|
svc->notify = parse_notify(notify);
|
||||||
svc->notify = type;
|
else
|
||||||
} else if (svc->notify) {
|
svc->notify = readiness;
|
||||||
disable_notify:
|
|
||||||
/* XXX: close existing socket */
|
|
||||||
svc->notify = 0;
|
|
||||||
}
|
|
||||||
if (desc)
|
if (desc)
|
||||||
strlcpy(svc->desc, desc, sizeof(svc->desc));
|
strlcpy(svc->desc, desc, sizeof(svc->desc));
|
||||||
else if (type == SVC_TYPE_TTY)
|
else if (type == SVC_TYPE_TTY)
|
||||||
@@ -2364,11 +2395,7 @@ restart:
|
|||||||
char condstr[MAX_COND_LEN];
|
char condstr[MAX_COND_LEN];
|
||||||
|
|
||||||
dbg("%s: stopped, cleaning up timers and conditions ...", svc_ident(svc, NULL, 0));
|
dbg("%s: stopped, cleaning up timers and conditions ...", svc_ident(svc, NULL, 0));
|
||||||
if (svc->notify && svc->notify_watcher.fd > 0) {
|
service_notify_stop(svc);
|
||||||
uev_io_stop(&svc->notify_watcher);
|
|
||||||
close(svc->notify_watcher.fd);
|
|
||||||
svc->notify_watcher.fd = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
service_timeout_cancel(svc);
|
service_timeout_cancel(svc);
|
||||||
cond_clear(mkcond(svc, condstr, sizeof(condstr)));
|
cond_clear(mkcond(svc, condstr, sizeof(condstr)));
|
||||||
@@ -2522,6 +2549,8 @@ restart:
|
|||||||
|
|
||||||
svc_mark_clean(svc);
|
svc_mark_clean(svc);
|
||||||
}
|
}
|
||||||
|
if (svc->notify == SVC_NOTIFY_NONE)
|
||||||
|
service_ready(svc);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -2546,16 +2575,21 @@ restart:
|
|||||||
svc_set_state(svc, SVC_RUNNING_STATE);
|
svc_set_state(svc, SVC_RUNNING_STATE);
|
||||||
/* Reassert condition if we go from waiting and no change */
|
/* Reassert condition if we go from waiting and no change */
|
||||||
if (!svc_is_changed(svc)) {
|
if (!svc_is_changed(svc)) {
|
||||||
char name[MAX_COND_LEN];
|
if (svc->notify == SVC_NOTIFY_PID) {
|
||||||
|
char name[MAX_COND_LEN];
|
||||||
|
|
||||||
mkcond(svc, name, sizeof(name));
|
mkcond(svc, name, sizeof(name));
|
||||||
dbg("Reassert condition %s", name);
|
dbg("Reassert condition %s", name);
|
||||||
cond_set_path(cond_path(name), COND_ON);
|
cond_set_path(cond_path(name), COND_ON);
|
||||||
|
}
|
||||||
|
|
||||||
|
dbg("Reassert %s ready condition", svc_ident(svc, NULL, 0));
|
||||||
|
service_ready(svc);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case COND_OFF:
|
case COND_OFF:
|
||||||
dbg("Condition for %s is off, sending SIGCONT + SIGTERM", svc->name);
|
dbg("Condition for %s is off, sending SIGCONT + SIGTERM", svc_ident(svc, NULL, 0));
|
||||||
kill(svc->pid, SIGCONT);
|
kill(svc->pid, SIGCONT);
|
||||||
service_stop(svc);
|
service_stop(svc);
|
||||||
break;
|
break;
|
||||||
@@ -2677,13 +2711,13 @@ void service_notify_reconf(void)
|
|||||||
svc_t *svc, *iter = NULL;
|
svc_t *svc, *iter = NULL;
|
||||||
|
|
||||||
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
|
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
|
||||||
if (!svc->notify)
|
if (svc->notify == SVC_NOTIFY_PID)
|
||||||
continue; /* managed by pidfile plugin */
|
continue; /* managed by pidfile plugin */
|
||||||
|
|
||||||
if (svc->state != SVC_RUNNING_STATE)
|
if (svc->state != SVC_RUNNING_STATE)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (svc_is_changed(svc) || svc_is_starting(svc))
|
if (svc->notify != SVC_NOTIFY_NONE && (svc_is_changed(svc) || svc_is_starting(svc)))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
service_ready(svc);
|
service_ready(svc);
|
||||||
@@ -2730,7 +2764,7 @@ void service_notify_cb(uev_t *w, void *arg, int events)
|
|||||||
service_ready(svc);
|
service_ready(svc);
|
||||||
|
|
||||||
/* s6 applications close their socket after notification */
|
/* s6 applications close their socket after notification */
|
||||||
if (svc->notify == 2) {
|
if (svc->notify == SVC_NOTIFY_S6) {
|
||||||
uev_io_stop(w);
|
uev_io_stop(w);
|
||||||
close(w->fd);
|
close(w->fd);
|
||||||
w->fd = 0;
|
w->fd = 0;
|
||||||
|
|||||||
@@ -216,7 +216,7 @@ restart:
|
|||||||
service_step_all(SVC_TYPE_ANY);
|
service_step_all(SVC_TYPE_ANY);
|
||||||
|
|
||||||
/* Allow runparts to start */
|
/* Allow runparts to start */
|
||||||
cond_set("int/bootstrap");
|
cond_set_oneshot("int/bootstrap");
|
||||||
|
|
||||||
if (sm->newlevel == -1)
|
if (sm->newlevel == -1)
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -83,6 +83,14 @@ typedef enum {
|
|||||||
SVC_ONCRASH_SCRIPT,
|
SVC_ONCRASH_SCRIPT,
|
||||||
} svc_oncrash_action_t;
|
} svc_oncrash_action_t;
|
||||||
|
|
||||||
|
/* 0: none, 1: systemd, 2: s6 */
|
||||||
|
typedef enum {
|
||||||
|
SVC_NOTIFY_NONE = 0,
|
||||||
|
SVC_NOTIFY_PID,
|
||||||
|
SVC_NOTIFY_SYSTEMD,
|
||||||
|
SVC_NOTIFY_S6,
|
||||||
|
} svc_notify_t;
|
||||||
|
|
||||||
#define MAX_ID_LEN 16
|
#define MAX_ID_LEN 16
|
||||||
#define MAX_ARG_LEN 64
|
#define MAX_ARG_LEN 64
|
||||||
#define MAX_CMD_LEN 256
|
#define MAX_CMD_LEN 256
|
||||||
@@ -202,7 +210,7 @@ typedef struct svc {
|
|||||||
/*
|
/*
|
||||||
* Readiness notification socket: systemd, s6
|
* Readiness notification socket: systemd, s6
|
||||||
*/
|
*/
|
||||||
int notify; /* 0: none, 1: systemd, 2: s6 */
|
svc_notify_t notify;
|
||||||
uev_t notify_watcher; /* i/o watcher */
|
uev_t notify_watcher; /* i/o watcher */
|
||||||
|
|
||||||
/* time at svc_del(), used by gc timer */
|
/* time at svc_del(), used by gc timer */
|
||||||
|
|||||||
@@ -18,23 +18,23 @@
|
|||||||
# change the contents any way you like, it can even be empty.
|
# change the contents any way you like, it can even be empty.
|
||||||
|
|
||||||
# Check for systemd-udevd and eudev, if we find both, we opt for the latter.
|
# Check for systemd-udevd and eudev, if we find both, we opt for the latter.
|
||||||
service nowarn [S12345789] cgroup.system name:udevd pid:udevd log /lib/systemd/systemd-udevd -- Device event daemon (udev)
|
service nowarn [S12345789] cgroup.system name:udevd notify:none pid:udevd log /lib/systemd/systemd-udevd -- Device event daemon (udev)
|
||||||
service nowarn [S12345789] cgroup.system name:udevd pid:udevd log udevd -D -- Device event daemon (udev)
|
service nowarn [S12345789] cgroup.system name:udevd notify:none pid:udevd log udevd -D -- Device event daemon (udev)
|
||||||
|
|
||||||
# Wait for udevd to start, then trigger coldplug events and module loading.
|
# Wait for udevd to start, then trigger coldplug events and module loading.
|
||||||
# The last 'settle' call waits for it to finalize processing all uevents.
|
# The last 'settle' call waits for it to finalize processing all uevents.
|
||||||
run nowarn if:udevd cgroup.init :1 [S] <pid/udevd> log udevadm settle -t 0 --
|
run nowarn if:udevd cgroup.init :1 [S] <service/udevd/ready> log udevadm settle -t 0 --
|
||||||
run nowarn if:udevd cgroup.init :2 [S] <pid/udevd> log udevadm control --reload --
|
run nowarn if:udevd cgroup.init :2 [S] <service/udevd/ready> log udevadm control --reload --
|
||||||
run nowarn if:udevd cgroup.init :3 [S] <pid/udevd> log udevadm trigger -c add -t devices -- Requesting device events
|
run nowarn if:udevd cgroup.init :3 [S] <service/udevd/ready> log udevadm trigger -c add -t devices -- Requesting device events
|
||||||
run nowarn if:udevd cgroup.init :4 [S] <pid/udevd> log udevadm trigger -c add -t subsystems -- Requesting subsystem events
|
run nowarn if:udevd cgroup.init :4 [S] <service/udevd/ready> log udevadm trigger -c add -t subsystems -- Requesting subsystem events
|
||||||
run nowarn if:udevd cgroup.init :5 [S] <pid/udevd> log udevadm settle -t 30 -- Waiting for udev to finish
|
run nowarn if:udevd cgroup.init :5 [S] <service/udevd/ready> log udevadm settle -t 30 -- Waiting for udev to finish
|
||||||
|
|
||||||
# If udevd is not available, check for mdevd. Unlike plain 'mdev -df', the
|
# If udevd is not available, check for mdevd. Unlike plain 'mdev -df', the
|
||||||
# mdevd-coldplug process exits when mdevd has completed. So the condition
|
# mdevd-coldplug process exits when mdevd has completed. So the condition
|
||||||
# <run/coldplug/success> (same as for plain mdev below) can be relied on as a
|
# <run/coldplug/success> (same as for plain mdev below) can be relied on as a
|
||||||
# barrier for services that, e.g., need to probe for switchcore ports or PHYs
|
# barrier for services that, e.g., need to probe for switchcore ports or PHYs
|
||||||
# that require firmware loading before they show up.
|
# that require firmware loading before they show up.
|
||||||
service nowarn conflict:udevd,mdev cgroup.init if:!udevd \
|
service nowarn conflict:udevd,mdev cgroup.init notify:none if:!udevd \
|
||||||
[S12345789] notify:s6 mdevd -O 4 -D %n -- Device event daemon (mdevd)
|
[S12345789] notify:s6 mdevd -O 4 -D %n -- Device event daemon (mdevd)
|
||||||
run nowarn conflict:udevd,mdev cgroup.init name:coldplug <service/mdevd/ready> \
|
run nowarn conflict:udevd,mdev cgroup.init name:coldplug <service/mdevd/ready> \
|
||||||
[S] mdevd-coldplug -- Cold plugging system
|
[S] mdevd-coldplug -- Cold plugging system
|
||||||
@@ -42,7 +42,7 @@ run nowarn conflict:udevd,mdev cgroup.init name:coldplug <service/mdevd/read
|
|||||||
# If neither udevd or mdevd are available, fall back to mdev. The new daemon
|
# If neither udevd or mdevd are available, fall back to mdev. The new daemon
|
||||||
# mode calls `mdev -s` internally but does not create a PID file when that is
|
# mode calls `mdev -s` internally but does not create a PID file when that is
|
||||||
# done, so synchronization with coldplug is fragile.
|
# done, so synchronization with coldplug is fragile.
|
||||||
service nowarn conflict:udevd,mdevd cgroup.init if:!udevd,!mdevd \
|
service nowarn conflict:udevd,mdevd cgroup.init notify:none if:!udevd,!mdevd \
|
||||||
[S12345789] mdev -df -S -- Device event daemon (mdev)
|
[S12345789] mdev -df -S -- Device event daemon (mdev)
|
||||||
|
|
||||||
# Trigger a replay of all uevents from boot, before userspace was up and the
|
# Trigger a replay of all uevents from boot, before userspace was up and the
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# Test service, only used for `make check`, not for public use
|
# Test service, only used for `make check`, not for public use
|
||||||
service [S123456789] name:testserv pid:!/run/testserv.pid \
|
service [S123456789] name:testserv pid:!/run/testserv.pid \
|
||||||
<boot/testserv> cgroup.system \
|
<boot/testserv> cgroup.system notify:none \
|
||||||
/sbin/serv -n -p -i testserv -- Test serv daemon
|
/sbin/serv -n -p -i testserv -- Test serv daemon
|
||||||
|
|||||||
@@ -80,6 +80,9 @@ test_one()
|
|||||||
say "Done, drop stanza from $TEST_CONF ..."
|
say "Done, drop stanza from $TEST_CONF ..."
|
||||||
run "rm $TEST_CONF"
|
run "rm $TEST_CONF"
|
||||||
run "initctl reload"
|
run "initctl reload"
|
||||||
|
|
||||||
|
# Done, disable debug
|
||||||
|
run "initctl debug"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+9
-3
@@ -2,6 +2,11 @@
|
|||||||
set -eu
|
set -eu
|
||||||
|
|
||||||
TEST_DIR=$(dirname "$0")
|
TEST_DIR=$(dirname "$0")
|
||||||
|
# shellcheck disable=SC2034
|
||||||
|
BOOTSTRAP="foo=bar\n\
|
||||||
|
set COLORTERM=yes\n\
|
||||||
|
b aq=oroszoe\n\
|
||||||
|
baz=qux"
|
||||||
|
|
||||||
test_setup()
|
test_setup()
|
||||||
{
|
{
|
||||||
@@ -19,13 +24,14 @@ test_teardown()
|
|||||||
# shellcheck source=/dev/null
|
# shellcheck source=/dev/null
|
||||||
. "$TEST_DIR/lib/setup.sh"
|
. "$TEST_DIR/lib/setup.sh"
|
||||||
|
|
||||||
|
say "Waiting for runlevel 2"
|
||||||
|
sleep 2
|
||||||
|
|
||||||
#run "initctl debug"
|
#run "initctl debug"
|
||||||
say "Add custom envs to $FINIT_CONF ..."
|
|
||||||
run "echo 'foo=bar' > $FINIT_CONF"
|
|
||||||
run "echo 'baz=qux' >> $FINIT_CONF"
|
|
||||||
|
|
||||||
say "Add service stanza to $FINIT_CONF ..."
|
say "Add service stanza to $FINIT_CONF ..."
|
||||||
run "echo 'service serv -np -e foo:bar -- Verify foo=bar' >> $FINIT_CONF"
|
run "echo 'service serv -np -e foo:bar -- Verify foo=bar' >> $FINIT_CONF"
|
||||||
|
#run "cat $FINIT_CONF"
|
||||||
|
|
||||||
say 'Reload Finit'
|
say 'Reload Finit'
|
||||||
run "initctl reload"
|
run "initctl reload"
|
||||||
|
|||||||
@@ -5,3 +5,5 @@ foo=bar
|
|||||||
baz=qux
|
baz=qux
|
||||||
|
|
||||||
xyzzy=$foo
|
xyzzy=$foo
|
||||||
|
|
||||||
|
FOO_ARGS="-i $foo -l $xyzzy endarg"
|
||||||
|
|||||||
+1
-1
@@ -22,7 +22,7 @@ test_teardown()
|
|||||||
|
|
||||||
sep "/etc/env:"
|
sep "/etc/env:"
|
||||||
run "cat /etc/env"
|
run "cat /etc/env"
|
||||||
run "echo 'service env:/etc/env serv -np -e xyzzy:bar -- serv checks xyzzy=bar' > $FINIT_CONF"
|
run "echo 'service env:/etc/env serv -np -e xyzzy:bar -e \"FOO_ARGS:-i bar -l bar endarg\" -- serv checks xyzzy=bar' > $FINIT_CONF"
|
||||||
|
|
||||||
say 'Reload Finit'
|
say 'Reload Finit'
|
||||||
run "initctl reload"
|
run "initctl reload"
|
||||||
|
|||||||
+13
-12
@@ -14,10 +14,10 @@ TEST_DIR=$(dirname "$0")
|
|||||||
test_setup()
|
test_setup()
|
||||||
{
|
{
|
||||||
run "cat >> $FINIT_CONF" <<EOF
|
run "cat >> $FINIT_CONF" <<EOF
|
||||||
service log:stdout name:A serv -np -i A
|
service log:stdout notify:pid name:A serv -np -i A -- A (pid)
|
||||||
service log:stdout notify:systemd <pid/A> name:B serv -np -i B -N 0 -- B needs A
|
service log:stdout notify:systemd <pid/A> name:B serv -np -i B -N 0 -- B needs A (systemd)
|
||||||
service log:stdout notify:systemd <service/B/ready> name:C serv -np -i C -N 0 -- C needs B(service)
|
service log:stdout notify:s6 <service/B/ready> name:C serv -np -i C -N 0 -- C needs B (s6)
|
||||||
service log:stdout notify:systemd <pid/B> name:D serv -np -i D -N 0 -- D needs B(pid)
|
service log:stdout notify:none <pid/A> name:D type:forking serv -i D -- D needs A (forking)
|
||||||
task <service/C/ready,service/D/ready> name:allup initctl cond set allup -- Everything is up
|
task <service/C/ready,service/D/ready> name:allup initctl cond set allup -- Everything is up
|
||||||
EOF
|
EOF
|
||||||
say "Test start $(date)"
|
say "Test start $(date)"
|
||||||
@@ -41,17 +41,18 @@ run "cat $FINIT_CONF"
|
|||||||
sep
|
sep
|
||||||
run "initctl reload"
|
run "initctl reload"
|
||||||
run "initctl status"
|
run "initctl status"
|
||||||
|
run "initctl cond dump"
|
||||||
sep
|
sep
|
||||||
|
|
||||||
|
run "initctl debug"
|
||||||
say "waiting for primary startup to complete"
|
say "waiting for primary startup to complete"
|
||||||
retry 'assert_status allup "done"' 100 1
|
retry 'assert_status allup "done"' 10 1
|
||||||
assert_status C "running"
|
assert_status C "running"
|
||||||
oldpid=$(pidof C)
|
oldpid=$(pidof C)
|
||||||
assert_status D "running"
|
|
||||||
doldpid=$(pidof D)
|
|
||||||
|
|
||||||
sep "pre-reload status"
|
sep "pre-reload status"
|
||||||
run "initctl status"
|
run "initctl status"
|
||||||
|
run "initctl cond dump"
|
||||||
sep
|
sep
|
||||||
|
|
||||||
say "Reload Finit, who gets restarted?"
|
say "Reload Finit, who gets restarted?"
|
||||||
@@ -59,15 +60,15 @@ say "Reload Finit, who gets restarted?"
|
|||||||
run "initctl reload"
|
run "initctl reload"
|
||||||
sleep 2
|
sleep 2
|
||||||
|
|
||||||
|
sep "post-reload status"
|
||||||
|
run "initctl status"
|
||||||
|
run "initctl cond dump"
|
||||||
|
sep
|
||||||
|
|
||||||
assert_status A "running"
|
assert_status A "running"
|
||||||
assert_status B "running"
|
assert_status B "running"
|
||||||
assert_status C "running"
|
assert_status C "running"
|
||||||
assert_status D "running"
|
|
||||||
|
|
||||||
newpid=$(pidof C)
|
newpid=$(pidof C)
|
||||||
# shellcheck disable=SC2086
|
# shellcheck disable=SC2086
|
||||||
assert "C was not restarted" $oldpid -eq $newpid
|
assert "C was not restarted" $oldpid -eq $newpid
|
||||||
|
|
||||||
dnewpid=$(pidof D)
|
|
||||||
# shellcheck disable=SC2086
|
|
||||||
assert "D was not restarted" $doldpid -eq $dnewpid
|
|
||||||
|
|||||||
Reference in New Issue
Block a user