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.
|
||||
|
||||
|
||||
[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
|
||||
--------------------
|
||||
|
||||
@@ -1613,7 +1633,8 @@ Major bug fix 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.4]: https://github.com/troglobit/finit/compare/4.3...4.4
|
||||
[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/])
|
||||
AC_CONFIG_AUX_DIR(aux)
|
||||
AM_INIT_AUTOMAKE([1.11 foreign dist-xz subdir-objects])
|
||||
@@ -314,7 +314,8 @@ pkglibdir=$libdir/finit
|
||||
AC_SUBST(pkglibexecdir)
|
||||
AC_EXPAND_DIR(pkglibexecdir, "$libexecdir/finit")
|
||||
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_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
|
||||
extent.
|
||||
|
||||
As of Finit v4.4 partial support for systemd and s6 is available. The
|
||||
native PID file mode of operation is still default, the other's can be
|
||||
defined per service, like this:
|
||||
As of Finit v4.4 partial support for systemd and s6 style readiness
|
||||
notification is available, and the native PID file mode of operation is,
|
||||
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: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:
|
||||
|
||||
service notify:systemd A
|
||||
service <service/A/ready> B
|
||||
service notify:pid watchdogd
|
||||
service <service/watchdogd/ready> stress-ng --cpu 8
|
||||
|
||||
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.
|
||||
*/
|
||||
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);
|
||||
free(pidfn);
|
||||
} 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);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
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
|
||||
* readiness notification. Issue #343
|
||||
*/
|
||||
if (!svc->notify)
|
||||
if (svc->notify == SVC_NOTIFY_PID)
|
||||
svc_started(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)
|
||||
if (svc->notify == SVC_NOTIFY_PID)
|
||||
cond_set(cond);
|
||||
if (svc->notify == SVC_NOTIFY_PID || svc->notify == SVC_NOTIFY_NONE)
|
||||
service_ready(svc);
|
||||
} else if (mask & IN_DELETE) {
|
||||
cond_clear(cond);
|
||||
if (!svc->notify)
|
||||
if (svc->notify == SVC_NOTIFY_PID)
|
||||
service_ready(svc);
|
||||
}
|
||||
}
|
||||
@@ -240,7 +241,7 @@ static void pidfile_reconf(void *arg)
|
||||
if (svc_is_changed(svc) || svc_is_starting(svc))
|
||||
continue;
|
||||
|
||||
if (!svc->notify)
|
||||
if (svc->notify == SVC_NOTIFY_PID)
|
||||
service_ready(svc);
|
||||
|
||||
mkcond(svc, cond, sizeof(cond));
|
||||
|
||||
+34
-4
@@ -545,6 +545,23 @@ static void parse_env(char *line)
|
||||
*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);
|
||||
|
||||
node = malloc(sizeof(*node));
|
||||
@@ -958,6 +975,18 @@ static int parse_static(char *line, int is_rcsd)
|
||||
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)) {
|
||||
syncsec = strtonum(strip_line(x), 0, 60, NULL);
|
||||
return 0;
|
||||
@@ -1393,7 +1422,8 @@ static int conf_change_act(char *dir, char *name, uint32_t mask)
|
||||
struct conf_change *node;
|
||||
char *rp = NULL;
|
||||
|
||||
if (name[0])
|
||||
/* Check for actual printable characters, sometimes STX */
|
||||
if (name[0] && name[0] >= ' ')
|
||||
paste(fn, sizeof(fn), dir, name);
|
||||
else
|
||||
strlcpy(fn, dir, sizeof(fn));
|
||||
@@ -1579,7 +1609,7 @@ int conf_init(uev_ctx_t *ctx)
|
||||
*/
|
||||
#ifdef 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");
|
||||
}
|
||||
#endif
|
||||
@@ -1587,7 +1617,7 @@ int conf_init(uev_ctx_t *ctx)
|
||||
* Start kernel event daemon as soon as possible, if enabled
|
||||
*/
|
||||
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");
|
||||
|
||||
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)
|
||||
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",
|
||||
_PATH_RUNPARTS, args, runparts, runparts);
|
||||
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 kerndebug = 0; /* set if /proc/sys/kernel/printk > 7 */
|
||||
int syncsec = 0; /* reboot delay */
|
||||
int readiness = SVC_NOTIFY_PID;
|
||||
char *finit_conf= NULL;
|
||||
char *finit_rcsd= 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. */
|
||||
if (in_container())
|
||||
cond_set("int/container");
|
||||
cond_set_oneshot("int/container");
|
||||
|
||||
/*
|
||||
* Initialize .conf system and load static /etc/finit.conf then
|
||||
|
||||
@@ -121,6 +121,7 @@ extern int single;
|
||||
extern int bootstrap;
|
||||
extern int kerndebug;
|
||||
extern int syncsec;
|
||||
extern int readiness;
|
||||
extern char *fstab;
|
||||
extern char *sdown;
|
||||
extern char *network;
|
||||
|
||||
+77
-43
@@ -394,11 +394,8 @@ static int redirect(svc_t *svc)
|
||||
*/
|
||||
static void source_env(svc_t *svc)
|
||||
{
|
||||
char buf[LINE_SIZE];
|
||||
char *line;
|
||||
size_t len;
|
||||
char *buf, *val, *line, *fn;
|
||||
FILE *fp;
|
||||
char *fn;
|
||||
|
||||
fn = svc_getenv(svc);
|
||||
if (!fn)
|
||||
@@ -409,12 +406,19 @@ static void source_env(svc_t *svc)
|
||||
if (!fp)
|
||||
return;
|
||||
|
||||
buf = alloca(LINE_SIZE);
|
||||
val = alloca(LINE_SIZE);
|
||||
if (!buf || !val) {
|
||||
warn("Failed allocating temporary env buffer");
|
||||
return;
|
||||
}
|
||||
|
||||
line = buf;
|
||||
len = sizeof(buf);
|
||||
while (fgets(line, len, fp)) {
|
||||
while (fgets(line, LINE_SIZE, fp)) {
|
||||
char *key = chomp(line);
|
||||
wordexp_t we = { 0 };
|
||||
char *value, *end;
|
||||
size_t i;
|
||||
|
||||
/* skip any leading whitespace */
|
||||
while (isspace(*key))
|
||||
@@ -467,9 +471,30 @@ static void source_env(svc_t *svc)
|
||||
*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)) {
|
||||
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);
|
||||
break;
|
||||
|
||||
@@ -692,11 +717,12 @@ static int service_start(svc_t *svc)
|
||||
wordexp_t we = { 0 };
|
||||
int rc;
|
||||
|
||||
if (svc->notify) {
|
||||
if (svc->notify == SVC_NOTIFY_SYSTEMD || svc->notify == SVC_NOTIFY_S6) {
|
||||
if (client_command(INIT_CMD_NOTIFY_SOCKET)) {
|
||||
err(1, "%s: failed creating notify socket", svc_ident(svc, NULL, 0));
|
||||
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 {
|
||||
char val[20];
|
||||
|
||||
@@ -721,7 +747,7 @@ static int service_start(svc_t *svc)
|
||||
if (len == 0)
|
||||
break;
|
||||
|
||||
if (svc->notify) {
|
||||
if (svc->notify == SVC_NOTIFY_SYSTEMD || svc->notify == SVC_NOTIFY_S6) {
|
||||
char *ptr = strstr(arg, "%n");
|
||||
|
||||
if (ptr) {
|
||||
@@ -898,6 +924,19 @@ static void service_kill(svc_t *svc)
|
||||
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
|
||||
*/
|
||||
@@ -913,12 +952,7 @@ static void service_cleanup(svc_t *svc)
|
||||
logit(LOG_CRIT, "Failed removing service %s pidfile %s",
|
||||
svc_ident(svc, NULL, 0), fn);
|
||||
|
||||
/* Ensure we don't have any notify socket lingering */
|
||||
if (svc->notify && svc->notify_watcher.fd > 0) {
|
||||
uev_io_stop(&svc->notify_watcher);
|
||||
close(svc->notify_watcher.fd);
|
||||
svc->notify_watcher.fd = 0;
|
||||
}
|
||||
service_notify_stop(svc);
|
||||
|
||||
/* No longer running, update books. */
|
||||
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"))
|
||||
return 1;
|
||||
return SVC_NOTIFY_SYSTEMD;
|
||||
if (!strcmp(arg, "s6"))
|
||||
return 2;
|
||||
return 0; /* unsupported/disabled */
|
||||
return SVC_NOTIFY_S6;
|
||||
if (!strcmp(arg, "pid"))
|
||||
return SVC_NOTIFY_PID;
|
||||
return SVC_NOTIFY_NONE; /* unsupported/none */
|
||||
}
|
||||
|
||||
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
|
||||
svc->log.enabled = 0;
|
||||
}
|
||||
if (notify) {
|
||||
int type = parse_notify(notify);
|
||||
|
||||
if (type <= 0)
|
||||
goto disable_notify;
|
||||
svc->notify = type;
|
||||
} else if (svc->notify) {
|
||||
disable_notify:
|
||||
/* XXX: close existing socket */
|
||||
svc->notify = 0;
|
||||
}
|
||||
if (notify)
|
||||
svc->notify = parse_notify(notify);
|
||||
else
|
||||
svc->notify = readiness;
|
||||
|
||||
if (desc)
|
||||
strlcpy(svc->desc, desc, sizeof(svc->desc));
|
||||
else if (type == SVC_TYPE_TTY)
|
||||
@@ -2364,11 +2395,7 @@ restart:
|
||||
char condstr[MAX_COND_LEN];
|
||||
|
||||
dbg("%s: stopped, cleaning up timers and conditions ...", svc_ident(svc, NULL, 0));
|
||||
if (svc->notify && svc->notify_watcher.fd > 0) {
|
||||
uev_io_stop(&svc->notify_watcher);
|
||||
close(svc->notify_watcher.fd);
|
||||
svc->notify_watcher.fd = 0;
|
||||
}
|
||||
service_notify_stop(svc);
|
||||
|
||||
service_timeout_cancel(svc);
|
||||
cond_clear(mkcond(svc, condstr, sizeof(condstr)));
|
||||
@@ -2522,6 +2549,8 @@ restart:
|
||||
|
||||
svc_mark_clean(svc);
|
||||
}
|
||||
if (svc->notify == SVC_NOTIFY_NONE)
|
||||
service_ready(svc);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@@ -2546,16 +2575,21 @@ restart:
|
||||
svc_set_state(svc, SVC_RUNNING_STATE);
|
||||
/* Reassert condition if we go from waiting and no change */
|
||||
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));
|
||||
dbg("Reassert condition %s", name);
|
||||
cond_set_path(cond_path(name), COND_ON);
|
||||
mkcond(svc, name, sizeof(name));
|
||||
dbg("Reassert condition %s", name);
|
||||
cond_set_path(cond_path(name), COND_ON);
|
||||
}
|
||||
|
||||
dbg("Reassert %s ready condition", svc_ident(svc, NULL, 0));
|
||||
service_ready(svc);
|
||||
}
|
||||
break;
|
||||
|
||||
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);
|
||||
service_stop(svc);
|
||||
break;
|
||||
@@ -2677,13 +2711,13 @@ void service_notify_reconf(void)
|
||||
svc_t *svc, *iter = NULL;
|
||||
|
||||
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 */
|
||||
|
||||
if (svc->state != SVC_RUNNING_STATE)
|
||||
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;
|
||||
|
||||
service_ready(svc);
|
||||
@@ -2730,7 +2764,7 @@ void service_notify_cb(uev_t *w, void *arg, int events)
|
||||
service_ready(svc);
|
||||
|
||||
/* s6 applications close their socket after notification */
|
||||
if (svc->notify == 2) {
|
||||
if (svc->notify == SVC_NOTIFY_S6) {
|
||||
uev_io_stop(w);
|
||||
close(w->fd);
|
||||
w->fd = 0;
|
||||
|
||||
@@ -216,7 +216,7 @@ restart:
|
||||
service_step_all(SVC_TYPE_ANY);
|
||||
|
||||
/* Allow runparts to start */
|
||||
cond_set("int/bootstrap");
|
||||
cond_set_oneshot("int/bootstrap");
|
||||
|
||||
if (sm->newlevel == -1)
|
||||
break;
|
||||
|
||||
@@ -83,6 +83,14 @@ typedef enum {
|
||||
SVC_ONCRASH_SCRIPT,
|
||||
} 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_ARG_LEN 64
|
||||
#define MAX_CMD_LEN 256
|
||||
@@ -202,7 +210,7 @@ typedef struct svc {
|
||||
/*
|
||||
* Readiness notification socket: systemd, s6
|
||||
*/
|
||||
int notify; /* 0: none, 1: systemd, 2: s6 */
|
||||
svc_notify_t notify;
|
||||
uev_t notify_watcher; /* i/o watcher */
|
||||
|
||||
/* time at svc_del(), used by gc timer */
|
||||
|
||||
@@ -18,23 +18,23 @@
|
||||
# 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.
|
||||
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 pid:udevd log udevd -D -- 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 notify:none pid:udevd log udevd -D -- Device event daemon (udev)
|
||||
|
||||
# Wait for udevd to start, then trigger coldplug events and module loading.
|
||||
# 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 :2 [S] <pid/udevd> 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 :4 [S] <pid/udevd> 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 :1 [S] <service/udevd/ready> log udevadm settle -t 0 --
|
||||
run nowarn if:udevd cgroup.init :2 [S] <service/udevd/ready> log udevadm control --reload --
|
||||
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] <service/udevd/ready> log udevadm trigger -c add -t subsystems -- Requesting subsystem events
|
||||
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
|
||||
# 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
|
||||
# barrier for services that, e.g., need to probe for switchcore ports or PHYs
|
||||
# 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)
|
||||
run nowarn conflict:udevd,mdev cgroup.init name:coldplug <service/mdevd/ready> \
|
||||
[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
|
||||
# mode calls `mdev -s` internally but does not create a PID file when that is
|
||||
# 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)
|
||||
|
||||
# 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
|
||||
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
|
||||
|
||||
@@ -80,6 +80,9 @@ test_one()
|
||||
say "Done, drop stanza from $TEST_CONF ..."
|
||||
run "rm $TEST_CONF"
|
||||
run "initctl reload"
|
||||
|
||||
# Done, disable debug
|
||||
run "initctl debug"
|
||||
}
|
||||
|
||||
|
||||
|
||||
+9
-3
@@ -2,6 +2,11 @@
|
||||
set -eu
|
||||
|
||||
TEST_DIR=$(dirname "$0")
|
||||
# shellcheck disable=SC2034
|
||||
BOOTSTRAP="foo=bar\n\
|
||||
set COLORTERM=yes\n\
|
||||
b aq=oroszoe\n\
|
||||
baz=qux"
|
||||
|
||||
test_setup()
|
||||
{
|
||||
@@ -19,13 +24,14 @@ test_teardown()
|
||||
# shellcheck source=/dev/null
|
||||
. "$TEST_DIR/lib/setup.sh"
|
||||
|
||||
say "Waiting for runlevel 2"
|
||||
sleep 2
|
||||
|
||||
#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 ..."
|
||||
run "echo 'service serv -np -e foo:bar -- Verify foo=bar' >> $FINIT_CONF"
|
||||
#run "cat $FINIT_CONF"
|
||||
|
||||
say 'Reload Finit'
|
||||
run "initctl reload"
|
||||
|
||||
@@ -5,3 +5,5 @@ foo=bar
|
||||
baz=qux
|
||||
|
||||
xyzzy=$foo
|
||||
|
||||
FOO_ARGS="-i $foo -l $xyzzy endarg"
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ test_teardown()
|
||||
|
||||
sep "/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'
|
||||
run "initctl reload"
|
||||
|
||||
+13
-12
@@ -14,10 +14,10 @@ TEST_DIR=$(dirname "$0")
|
||||
test_setup()
|
||||
{
|
||||
run "cat >> $FINIT_CONF" <<EOF
|
||||
service log:stdout name:A serv -np -i A
|
||||
service log:stdout notify:systemd <pid/A> name:B serv -np -i B -N 0 -- B needs A
|
||||
service log:stdout notify:systemd <service/B/ready> name:C serv -np -i C -N 0 -- C needs B(service)
|
||||
service log:stdout notify:systemd <pid/B> name:D serv -np -i D -N 0 -- D needs B(pid)
|
||||
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 (systemd)
|
||||
service log:stdout notify:s6 <service/B/ready> name:C serv -np -i C -N 0 -- C needs B (s6)
|
||||
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
|
||||
EOF
|
||||
say "Test start $(date)"
|
||||
@@ -41,17 +41,18 @@ run "cat $FINIT_CONF"
|
||||
sep
|
||||
run "initctl reload"
|
||||
run "initctl status"
|
||||
run "initctl cond dump"
|
||||
sep
|
||||
|
||||
run "initctl debug"
|
||||
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"
|
||||
oldpid=$(pidof C)
|
||||
assert_status D "running"
|
||||
doldpid=$(pidof D)
|
||||
|
||||
sep "pre-reload status"
|
||||
run "initctl status"
|
||||
run "initctl cond dump"
|
||||
sep
|
||||
|
||||
say "Reload Finit, who gets restarted?"
|
||||
@@ -59,15 +60,15 @@ say "Reload Finit, who gets restarted?"
|
||||
run "initctl reload"
|
||||
sleep 2
|
||||
|
||||
sep "post-reload status"
|
||||
run "initctl status"
|
||||
run "initctl cond dump"
|
||||
sep
|
||||
|
||||
assert_status A "running"
|
||||
assert_status B "running"
|
||||
assert_status C "running"
|
||||
assert_status D "running"
|
||||
|
||||
newpid=$(pidof C)
|
||||
# shellcheck disable=SC2086
|
||||
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