mirror of
https://github.com/troglobit/finit.git
synced 2026-09-30 21:13:01 +07:00
conf: settle the block format's key names and value shapes
The initial implementation was done using a naive translator of the
legacy one-liner format key by key, so it inherited encodings that the
block format exists to remove: a timeout packed into a script path, a
small comma-and-colon language inside the log string, sigils standing in
for booleans, and a log key (services) carrying three (!) types.
Settled naming against systemd, OpenRC, FreeBSD rc.subr, s6 and SMF.
Match systemd's semantics, not its naming.
pid -> pidfile, plus pidfile-create for the rare case
where Finit writes the file rather than the daemon
environment -> envfile, since it names a file to source, and the
top-level environment {} block sets variables
pre/post/... -> exec-start-pre, exec-start-ready, exec-stop,
exec-stop-post, exec-reload, exec-cleanup, each
with its own -timeout instead of "SEC,script"
halt, kill -> stop-signal, stop-timeout
restart -> restart for the policy, restart-max for the count
log -> a block with file, priority and identity, where
/dev/null and /dev/console are spelled as paths
group -> group and extra-groups, no longer positional
nowarn -> a leading - on command, as on envfile
List-valued keys take plural names. Aliases are desc, cond, mod,
caps, env, halt and kill; an alias may abbreviate the canonical name
or preserve a legacy spelling, nothing else.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This commit is contained in:
+221
-80
@@ -193,6 +193,19 @@ static cfg_opt_t env_opts[] = {
|
||||
CFG_END()
|
||||
};
|
||||
|
||||
/*
|
||||
* log { file = "/var/log/foo" ... } -- where a service's output goes.
|
||||
* /dev/null and /dev/console are spelled as paths, so there is one way
|
||||
* to say it. An empty block means syslog with defaults; `log` cannot
|
||||
* also be a scalar, libconfuse rejects a name declared as both.
|
||||
*/
|
||||
static cfg_opt_t svclog_opts[] = {
|
||||
CFG_STR("file", NULL, CFGF_NODEFAULT),
|
||||
CFG_STR("priority", NULL, CFGF_NODEFAULT),
|
||||
CFG_STR("identity", NULL, CFGF_NODEFAULT),
|
||||
CFG_END()
|
||||
};
|
||||
|
||||
/* log { size = 200k count = 5 } -- Finit's own log rotation */
|
||||
static cfg_opt_t log_opts[] = {
|
||||
CFG_STR("size", NULL, CFGF_NODEFAULT),
|
||||
@@ -200,43 +213,59 @@ static cfg_opt_t log_opts[] = {
|
||||
CFG_END()
|
||||
};
|
||||
|
||||
/* a lifecycle script and the bound on how long it may run */
|
||||
#define EXEC_OPTS(nm) \
|
||||
CFG_STR(nm, NULL, CFGF_NODEFAULT), \
|
||||
CFG_INT(nm "-timeout", 0, CFGF_NODEFAULT)
|
||||
|
||||
/* service NAME[:ID] { ... }, shared with task/run/sysv */
|
||||
static cfg_opt_t svc_opts[] = {
|
||||
CFG_STR ("description", NULL, CFGF_NODEFAULT),
|
||||
CFG_STR ("desc", NULL, CFGF_NODEFAULT), /* alias */
|
||||
CFG_STR ("command", NULL, CFGF_NODEFAULT),
|
||||
CFG_STR ("exec", NULL, CFGF_NODEFAULT), /* alias */
|
||||
CFG_STR ("runlevel", NULL, CFGF_NODEFAULT),
|
||||
CFG_STR_LIST("condition", NULL, CFGF_NODEFAULT),
|
||||
CFG_STR_LIST("conditions", NULL, CFGF_NODEFAULT),
|
||||
CFG_STR_LIST("cond", NULL, CFGF_NODEFAULT), /* alias */
|
||||
CFG_STR ("user", NULL, CFGF_NODEFAULT),
|
||||
CFG_STR_LIST("group", NULL, CFGF_NODEFAULT),
|
||||
CFG_STR ("environment", NULL, CFGF_NODEFAULT),
|
||||
CFG_STR ("group", NULL, CFGF_NODEFAULT),
|
||||
CFG_STR_LIST("extra-groups", NULL, CFGF_NODEFAULT),
|
||||
CFG_STR ("envfile", NULL, CFGF_NODEFAULT),
|
||||
CFG_STR ("env", NULL, CFGF_NODEFAULT), /* alias */
|
||||
CFG_STR ("pid", NULL, CFGF_NODEFAULT),
|
||||
CFG_STR ("log", NULL, CFGF_NODEFAULT),
|
||||
CFG_STR ("pidfile", NULL, CFGF_NODEFAULT),
|
||||
CFG_BOOL ("pidfile-create", cfg_false, CFGF_NODEFAULT),
|
||||
CFG_STR ("notify", NULL, CFGF_NODEFAULT),
|
||||
CFG_STR ("type", NULL, CFGF_NODEFAULT),
|
||||
CFG_BOOL ("manual", cfg_false, CFGF_NODEFAULT),
|
||||
CFG_BOOL ("remain", cfg_false, CFGF_NODEFAULT),
|
||||
CFG_BOOL ("respawn", cfg_false, CFGF_NODEFAULT),
|
||||
CFG_BOOL ("nowarn", cfg_false, CFGF_NODEFAULT),
|
||||
CFG_STR ("restart", NULL, CFGF_NODEFAULT),
|
||||
CFG_INT ("restart_sec", 0, CFGF_NODEFAULT),
|
||||
CFG_INT ("restart-max", 0, CFGF_NODEFAULT),
|
||||
CFG_INT ("restart-sec", 0, CFGF_NODEFAULT),
|
||||
CFG_STR ("oncrash", NULL, CFGF_NODEFAULT),
|
||||
CFG_STR ("halt", NULL, CFGF_NODEFAULT),
|
||||
CFG_INT ("kill", 0, CFGF_NODEFAULT),
|
||||
CFG_STR ("pre", NULL, CFGF_NODEFAULT),
|
||||
CFG_STR ("post", NULL, CFGF_NODEFAULT),
|
||||
CFG_STR ("ready", NULL, CFGF_NODEFAULT),
|
||||
CFG_STR ("cleanup", NULL, CFGF_NODEFAULT),
|
||||
CFG_STR ("reload", NULL, CFGF_NODEFAULT),
|
||||
CFG_STR ("stop", NULL, CFGF_NODEFAULT),
|
||||
CFG_STR ("stop-signal", NULL, CFGF_NODEFAULT),
|
||||
CFG_STR ("halt", NULL, CFGF_NODEFAULT), /* alias */
|
||||
CFG_INT ("stop-timeout", 0, CFGF_NODEFAULT),
|
||||
CFG_INT ("kill", 0, CFGF_NODEFAULT), /* alias */
|
||||
|
||||
/* lifecycle scripts, each with its own bound */
|
||||
EXEC_OPTS("exec-start-pre"),
|
||||
EXEC_OPTS("exec-start-ready"),
|
||||
EXEC_OPTS("exec-stop"),
|
||||
EXEC_OPTS("exec-stop-post"),
|
||||
EXEC_OPTS("exec-reload"),
|
||||
EXEC_OPTS("exec-cleanup"),
|
||||
|
||||
CFG_STR_LIST("capabilities", NULL, CFGF_NODEFAULT),
|
||||
CFG_STR_LIST("caps", NULL, CFGF_NODEFAULT), /* alias */
|
||||
CFG_STR_LIST("conflict", NULL, CFGF_NODEFAULT),
|
||||
CFG_STR_LIST("conflicts", NULL, CFGF_NODEFAULT),
|
||||
CFG_STR ("if", NULL, CFGF_NODEFAULT),
|
||||
CFG_STR ("tty", NULL, CFGF_NODEFAULT),
|
||||
/*
|
||||
* MULTI is not about repetition here, it is the only way to tell
|
||||
* `log {}` from no log at all: libconfuse instantiates every
|
||||
* non-MULTI section, so cfg_size() would always answer 1.
|
||||
*/
|
||||
CFG_SEC ("log", svclog_opts, CFGF_MULTI),
|
||||
CFG_SEC ("cgroup", cgroup_opts, CFGF_MULTI | CFGF_TITLE | CFGF_KEYSTRVAL),
|
||||
CFG_SEC ("rlimit", rlimit_opts, CFGF_NONE),
|
||||
CFG_END()
|
||||
@@ -245,7 +274,7 @@ static cfg_opt_t svc_opts[] = {
|
||||
/* tty NAME { ... } -- all three legacy variants */
|
||||
static cfg_opt_t tty_opts[] = {
|
||||
CFG_STR ("runlevel", NULL, CFGF_NODEFAULT),
|
||||
CFG_STR_LIST("condition", NULL, CFGF_NODEFAULT),
|
||||
CFG_STR_LIST("conditions", NULL, CFGF_NODEFAULT),
|
||||
CFG_STR_LIST("cond", NULL, CFGF_NODEFAULT), /* alias */
|
||||
CFG_STR ("device", NULL, CFGF_NODEFAULT),
|
||||
CFG_INT ("baud", 0, CFGF_NODEFAULT),
|
||||
@@ -254,7 +283,6 @@ static cfg_opt_t tty_opts[] = {
|
||||
CFG_BOOL ("nowait", cfg_false, CFGF_NODEFAULT),
|
||||
CFG_BOOL ("nologin", cfg_false, CFGF_NODEFAULT),
|
||||
CFG_STR ("command", NULL, CFGF_NODEFAULT),
|
||||
CFG_STR ("exec", NULL, CFGF_NODEFAULT), /* alias */
|
||||
CFG_BOOL ("notty", cfg_false, CFGF_NODEFAULT),
|
||||
CFG_BOOL ("rescue", cfg_false, CFGF_NODEFAULT),
|
||||
CFG_END()
|
||||
@@ -275,8 +303,8 @@ static cfg_opt_t conf_opts[] = {
|
||||
/* static/bootstrap directives */
|
||||
CFG_INT ("runlevel", 0, CFGF_NODEFAULT),
|
||||
CFG_STR ("hostname", NULL, CFGF_NODEFAULT),
|
||||
CFG_STR ("host", NULL, CFGF_NODEFAULT), /* alias */
|
||||
CFG_STR_LIST("module", NULL, CFGF_NODEFAULT),
|
||||
CFG_STR_LIST("modules", NULL, CFGF_NODEFAULT),
|
||||
CFG_STR_LIST("mod", NULL, CFGF_NODEFAULT), /* alias */
|
||||
CFG_STR_LIST("mknod", NULL, CFGF_NODEFAULT),
|
||||
CFG_STR ("network", NULL, CFGF_NODEFAULT),
|
||||
CFG_STR ("rcsd", NULL, CFGF_NODEFAULT),
|
||||
@@ -960,15 +988,33 @@ static void cfg_error_quiet(cfg_t *cfg, const char *fmt, va_list ap)
|
||||
/*
|
||||
* Alias helpers: canonical key wins, alias accepted.
|
||||
*/
|
||||
static const char *sec_getstr(cfg_t *sec, const char *key, const char *alias)
|
||||
/* which of KEY or ALIAS the user actually set, canonical wins */
|
||||
static const char *sec_key(cfg_t *sec, const char *key, const char *alias)
|
||||
{
|
||||
if (cfg_size(sec, key))
|
||||
return cfg_getstr(sec, key);
|
||||
return key;
|
||||
if (alias && cfg_size(sec, alias))
|
||||
return cfg_getstr(sec, alias);
|
||||
return alias;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char *sec_getstr(cfg_t *sec, const char *key, const char *alias)
|
||||
{
|
||||
key = sec_key(sec, key, alias);
|
||||
|
||||
return key ? cfg_getstr(sec, key) : NULL;
|
||||
}
|
||||
|
||||
static int sec_getint(cfg_t *sec, const char *key, const char *alias, long *val)
|
||||
{
|
||||
key = sec_key(sec, key, alias);
|
||||
if (!key)
|
||||
return 0;
|
||||
*val = cfg_getint(sec, key);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static char *sec_getlist(cfg_t *sec, const char *key, const char *alias, char *buf, size_t len)
|
||||
{
|
||||
unsigned int i, num;
|
||||
@@ -1082,6 +1128,73 @@ static void rlimit_translate(cfg_t *sec, struct rlimit arr[])
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* exec-NAME [+ exec-NAME-timeout] -> legacy "tok:[SEC,]script"
|
||||
*/
|
||||
static void addscript(char *line, size_t len, cfg_t *sec, const char *key,
|
||||
const char *tok)
|
||||
{
|
||||
char tmo[64];
|
||||
const char *str;
|
||||
char buf[512];
|
||||
|
||||
str = sec_getstr(sec, key, NULL);
|
||||
if (!str)
|
||||
return;
|
||||
|
||||
snprintf(tmo, sizeof(tmo), "%s-timeout", key);
|
||||
if (cfg_size(sec, tmo))
|
||||
snprintf(buf, sizeof(buf), "%ld,%s", cfg_getint(sec, tmo), str);
|
||||
else
|
||||
strlcpy(buf, str, sizeof(buf));
|
||||
|
||||
addopt(line, len, tok, buf);
|
||||
}
|
||||
|
||||
/*
|
||||
* log { file = "..." priority = "..." identity = "..." } -> legacy
|
||||
* "log" or "log:file,prio:P,tag:I". An empty block is syslog with
|
||||
* defaults; /dev/null and /dev/console arrive here as a file.
|
||||
*/
|
||||
static void addlog(char *line, size_t len, cfg_t *sec, char *file)
|
||||
{
|
||||
unsigned int num = cfg_size(sec, "log");
|
||||
char buf[512] = "";
|
||||
const char *str;
|
||||
cfg_t *log;
|
||||
|
||||
if (!num)
|
||||
return;
|
||||
|
||||
log = cfg_getnsec(sec, "log", num - 1);
|
||||
if (!log)
|
||||
return;
|
||||
|
||||
if (num > 1)
|
||||
logit(LOG_WARNING, "%s: %s declares %u log blocks, using the last",
|
||||
file, cfg_title(sec), num);
|
||||
|
||||
if ((str = sec_getstr(log, "file", NULL)))
|
||||
strlcpy(buf, str, sizeof(buf));
|
||||
if ((str = sec_getstr(log, "priority", NULL))) {
|
||||
if (buf[0])
|
||||
strlcat(buf, ",", sizeof(buf));
|
||||
strlcat(buf, "prio:", sizeof(buf));
|
||||
strlcat(buf, str, sizeof(buf));
|
||||
}
|
||||
if ((str = sec_getstr(log, "identity", NULL))) {
|
||||
if (buf[0])
|
||||
strlcat(buf, ",", sizeof(buf));
|
||||
strlcat(buf, "tag:", sizeof(buf));
|
||||
strlcat(buf, str, sizeof(buf));
|
||||
}
|
||||
|
||||
if (buf[0])
|
||||
addopt(line, len, "log:", buf);
|
||||
else
|
||||
addtok(line, len, "log");
|
||||
}
|
||||
|
||||
/*
|
||||
* Translate service/task/run/sysv section to the canonical legacy
|
||||
* one-liner and register through the same path as legacy files.
|
||||
@@ -1090,23 +1203,30 @@ static void svc_translate(cfg_t *sec, int type, struct rlimit rlimit[], char *fi
|
||||
{
|
||||
struct rlimit local_rlimit[RLIMIT_NLIMITS];
|
||||
char line[LINE_SIZE] = "";
|
||||
const char *str, *cmd;
|
||||
unsigned int num;
|
||||
const char *str, *cmd, *grp;
|
||||
unsigned int cnt;
|
||||
int nowarn, own;
|
||||
long num;
|
||||
char buf[512];
|
||||
char nm[80];
|
||||
char *id;
|
||||
|
||||
cmd = sec_getstr(sec, "command", "exec");
|
||||
cmd = sec_getstr(sec, "command", NULL);
|
||||
if (!cmd) {
|
||||
logit(LOG_ERR, "%s: section '%s' missing command, skipping",
|
||||
file, cfg_title(sec));
|
||||
return;
|
||||
}
|
||||
|
||||
/* a leading - tolerates a missing binary, cf. systemd ExecStart=- */
|
||||
nowarn = cmd[0] == '-';
|
||||
if (nowarn)
|
||||
cmd++;
|
||||
|
||||
if ((str = sec_getstr(sec, "runlevel", NULL)))
|
||||
addtok(line, sizeof(line), "[%s]", str);
|
||||
|
||||
if (sec_getlist(sec, "condition", "cond", buf, sizeof(buf)))
|
||||
if (sec_getlist(sec, "conditions", "cond", buf, sizeof(buf)))
|
||||
addtok(line, sizeof(line), "<%s>", buf);
|
||||
|
||||
/* section title is the identity: NAME[:ID], %i in templates */
|
||||
@@ -1118,29 +1238,39 @@ static void svc_translate(cfg_t *sec, int type, struct rlimit rlimit[], char *fi
|
||||
if (id && *id)
|
||||
addtok(line, sizeof(line), ":%s", id);
|
||||
|
||||
/* @user[:group[,supplementary,...]], first group is primary */
|
||||
/* @user[:group[,extra,...]] */
|
||||
str = sec_getstr(sec, "user", NULL);
|
||||
if (sec_getlist(sec, "group", NULL, buf, sizeof(buf)))
|
||||
addtok(line, sizeof(line), "@%s:%s", str ? str : "root", buf);
|
||||
grp = sec_getstr(sec, "group", NULL);
|
||||
if (sec_getlist(sec, "extra-groups", NULL, buf, sizeof(buf)))
|
||||
addtok(line, sizeof(line), "@%s:%s,%s", str ? str : "root",
|
||||
grp ? grp : "root", buf);
|
||||
else if (grp)
|
||||
addtok(line, sizeof(line), "@%s:%s", str ? str : "root", grp);
|
||||
else if (str)
|
||||
addtok(line, sizeof(line), "@%s", str);
|
||||
|
||||
if ((str = sec_getstr(sec, "environment", "env")))
|
||||
if ((str = sec_getstr(sec, "envfile", "env")))
|
||||
addopt(line, sizeof(line), "env:", str);
|
||||
|
||||
if ((str = sec_getstr(sec, "log", NULL))) {
|
||||
if (!strcmp(str, "true"))
|
||||
addtok(line, sizeof(line), "log");
|
||||
else if (strcmp(str, "false"))
|
||||
addopt(line, sizeof(line), "log:", str);
|
||||
}
|
||||
addlog(line, sizeof(line), sec, file);
|
||||
|
||||
if ((str = sec_getstr(sec, "pid", NULL))) {
|
||||
if (!strcmp(str, "true"))
|
||||
addtok(line, sizeof(line), "pid");
|
||||
else if (strcmp(str, "false"))
|
||||
addopt(line, sizeof(line), "pid:", str);
|
||||
}
|
||||
/*
|
||||
* The daemon owns its pidfile unless told otherwise, so the
|
||||
* legacy ! is the default here and pidfile-create drops it.
|
||||
*/
|
||||
/*
|
||||
* The daemon owns its pidfile unless told otherwise, so the
|
||||
* legacy ! is the default here and pidfile-create drops it. A
|
||||
* daemon-owned default path needs no token, that is what the
|
||||
* pidfile plugin discovers on its own.
|
||||
*/
|
||||
str = sec_getstr(sec, "pidfile", NULL);
|
||||
own = sec_getbool(sec, "pidfile-create");
|
||||
|
||||
if (str && strcmp(str, "true") && strcmp(str, "false"))
|
||||
addopt(line, sizeof(line), own ? "pid:" : "pid:!", str);
|
||||
else if (own)
|
||||
addtok(line, sizeof(line), "pid");
|
||||
|
||||
if ((str = sec_getstr(sec, "notify", NULL)))
|
||||
addtok(line, sizeof(line), "notify:%s", str);
|
||||
@@ -1159,41 +1289,47 @@ static void svc_translate(cfg_t *sec, int type, struct rlimit rlimit[], char *fi
|
||||
addtok(line, sizeof(line), "remain:yes");
|
||||
if (sec_getbool(sec, "respawn"))
|
||||
addtok(line, sizeof(line), "respawn");
|
||||
if (sec_getbool(sec, "nowarn"))
|
||||
if (nowarn)
|
||||
addtok(line, sizeof(line), "nowarn");
|
||||
|
||||
if ((str = sec_getstr(sec, "restart", NULL))) {
|
||||
if (!strcmp(str, "never"))
|
||||
addtok(line, sizeof(line), "norestart");
|
||||
else
|
||||
addtok(line, sizeof(line), "restart:%s", str);
|
||||
/*
|
||||
* restart is the policy, restart-max the count. true is the
|
||||
* default policy and needs no token unless a count came with it.
|
||||
*/
|
||||
str = sec_getstr(sec, "restart", NULL);
|
||||
if (!str)
|
||||
str = "true";
|
||||
if (!strcmp(str, "never") || !strcmp(str, "false"))
|
||||
addtok(line, sizeof(line), "norestart");
|
||||
else if (!strcmp(str, "always"))
|
||||
addtok(line, sizeof(line), "restart:always");
|
||||
else {
|
||||
if (strcmp(str, "true"))
|
||||
logit(LOG_WARNING, "%s: unknown restart '%s', assuming true",
|
||||
file, str);
|
||||
if (sec_getint(sec, "restart-max", NULL, &num))
|
||||
addtok(line, sizeof(line), "restart:%ld", num);
|
||||
}
|
||||
if (cfg_size(sec, "restart_sec"))
|
||||
addtok(line, sizeof(line), "restart_sec:%ld", cfg_getint(sec, "restart_sec"));
|
||||
|
||||
if (sec_getint(sec, "restart-sec", NULL, &num))
|
||||
addtok(line, sizeof(line), "restart_sec:%ld", num);
|
||||
|
||||
if ((str = sec_getstr(sec, "oncrash", NULL)))
|
||||
addtok(line, sizeof(line), "oncrash:%s", str);
|
||||
if ((str = sec_getstr(sec, "halt", NULL)))
|
||||
if ((str = sec_getstr(sec, "stop-signal", "halt")))
|
||||
addtok(line, sizeof(line), "halt:%s", str);
|
||||
if (cfg_size(sec, "kill"))
|
||||
addtok(line, sizeof(line), "kill:%ld", cfg_getint(sec, "kill"));
|
||||
if (sec_getint(sec, "stop-timeout", "kill", &num))
|
||||
addtok(line, sizeof(line), "kill:%ld", num);
|
||||
|
||||
if ((str = sec_getstr(sec, "pre", NULL)))
|
||||
addopt(line, sizeof(line), "pre:", str);
|
||||
if ((str = sec_getstr(sec, "post", NULL)))
|
||||
addopt(line, sizeof(line), "post:", str);
|
||||
if ((str = sec_getstr(sec, "ready", NULL)))
|
||||
addopt(line, sizeof(line), "ready:", str);
|
||||
if ((str = sec_getstr(sec, "cleanup", NULL)))
|
||||
addopt(line, sizeof(line), "cleanup:", str);
|
||||
if ((str = sec_getstr(sec, "reload", NULL)))
|
||||
addopt(line, sizeof(line), "reload:", str);
|
||||
if ((str = sec_getstr(sec, "stop", NULL)))
|
||||
addopt(line, sizeof(line), "stop:", str);
|
||||
addscript(line, sizeof(line), sec, "exec-start-pre", "pre:");
|
||||
addscript(line, sizeof(line), sec, "exec-start-ready", "ready:");
|
||||
addscript(line, sizeof(line), sec, "exec-stop", "stop:");
|
||||
addscript(line, sizeof(line), sec, "exec-stop-post", "post:");
|
||||
addscript(line, sizeof(line), sec, "exec-reload", "reload:");
|
||||
addscript(line, sizeof(line), sec, "exec-cleanup", "cleanup:");
|
||||
|
||||
if (sec_getlist(sec, "capabilities", "caps", buf, sizeof(buf)))
|
||||
addtok(line, sizeof(line), "caps:%s", buf);
|
||||
if (sec_getlist(sec, "conflict", NULL, buf, sizeof(buf)))
|
||||
if (sec_getlist(sec, "conflicts", NULL, buf, sizeof(buf)))
|
||||
addtok(line, sizeof(line), "conflict:%s", buf);
|
||||
|
||||
if ((str = sec_getstr(sec, "if", NULL)))
|
||||
@@ -1206,13 +1342,13 @@ static void svc_translate(cfg_t *sec, int type, struct rlimit rlimit[], char *fi
|
||||
* service joins exactly one group, so on duplicates the last
|
||||
* one wins, like a repeated token in a legacy one-liner.
|
||||
*/
|
||||
num = cfg_size(sec, "cgroup");
|
||||
if (num) {
|
||||
cfg_t *cg = cfg_getnsec(sec, "cgroup", num - 1);
|
||||
cnt = cfg_size(sec, "cgroup");
|
||||
if (cnt) {
|
||||
cfg_t *cg = cfg_getnsec(sec, "cgroup", cnt - 1);
|
||||
|
||||
if (num > 1)
|
||||
if (cnt > 1)
|
||||
logit(LOG_WARNING, "%s: %s declares %u cgroup blocks,"
|
||||
" using '%s'", file, cfg_title(sec), num,
|
||||
" using '%s'", file, cfg_title(sec), cnt,
|
||||
cfg_title(cg));
|
||||
|
||||
cgroup_settings(cg, buf, sizeof(buf));
|
||||
@@ -1252,11 +1388,15 @@ static void tty_translate(cfg_t *sec, struct rlimit rlimit[], char *file)
|
||||
if ((str = sec_getstr(sec, "runlevel", NULL)))
|
||||
addtok(line, sizeof(line), "[%s]", str);
|
||||
|
||||
if (sec_getlist(sec, "condition", "cond", buf, sizeof(buf)))
|
||||
if (sec_getlist(sec, "conditions", "cond", buf, sizeof(buf)))
|
||||
addtok(line, sizeof(line), "<%s>", buf);
|
||||
|
||||
dev = sec_getstr(sec, "device", NULL);
|
||||
cmd = sec_getstr(sec, "command", "exec");
|
||||
cmd = sec_getstr(sec, "command", NULL);
|
||||
if (cmd && cmd[0] == '-') {
|
||||
addtok(line, sizeof(line), "nowarn");
|
||||
cmd++;
|
||||
}
|
||||
|
||||
if (dev) {
|
||||
addtok(line, sizeof(line), "%s", dev);
|
||||
@@ -1320,11 +1460,11 @@ static void env_translate(cfg_t *cfg, const char *section)
|
||||
*/
|
||||
static void conf_parse_statics(cfg_t *cfg)
|
||||
{
|
||||
const char *str, *key;
|
||||
unsigned int i;
|
||||
const char *str;
|
||||
|
||||
if (BOOTSTRAP) {
|
||||
if ((str = sec_getstr(cfg, "hostname", "host"))) {
|
||||
if ((str = sec_getstr(cfg, "hostname", NULL))) {
|
||||
if (hostname)
|
||||
free(hostname);
|
||||
hostname = strdup(str);
|
||||
@@ -1339,8 +1479,9 @@ static void conf_parse_statics(cfg_t *cfg)
|
||||
run_interactive(cmd, "Creating device node %s", dev);
|
||||
}
|
||||
|
||||
for (i = 0; i < cfg_size(cfg, "module"); i++)
|
||||
kmod_load(cfg_getnstr(cfg, "module", i));
|
||||
key = sec_key(cfg, "modules", "mod");
|
||||
for (i = 0; key && i < cfg_size(cfg, key); i++)
|
||||
kmod_load(cfg_getnstr(cfg, key, i));
|
||||
|
||||
if ((str = sec_getstr(cfg, "network", NULL))) {
|
||||
if (network)
|
||||
|
||||
+54
-3
@@ -23,7 +23,7 @@ run envprobe {\n\
|
||||
test_teardown()
|
||||
{
|
||||
say "Running test teardown."
|
||||
run "rm -f $FINIT_CONF /tmp/envprobe-*"
|
||||
run "rm -f $FINIT_CONF /tmp/envprobe-* /tmp/pre /run/blockfmt.pid /run/notmine.pid"
|
||||
run "rm -f $FINIT_RCSD/legacy-side.conf"
|
||||
}
|
||||
|
||||
@@ -65,8 +65,8 @@ say "Add new-format service block in $FINIT_CONF"
|
||||
run "echo 'service service.sh {' > $FINIT_CONF"
|
||||
run "echo ' description = \"Test service\"' >> $FINIT_CONF"
|
||||
run "echo ' runlevel = \"2345\"' >> $FINIT_CONF"
|
||||
run "echo ' kill = 20' >> $FINIT_CONF"
|
||||
run "echo ' log = true' >> $FINIT_CONF"
|
||||
run "echo ' stop-timeout = 20' >> $FINIT_CONF"
|
||||
run "echo ' log { }' >> $FINIT_CONF"
|
||||
# Exercises the cgroup translation path. Whether the group is really
|
||||
# joined cannot be asserted here, cgroup_avail() is false inside the
|
||||
# test namespace, so initctl reports no cgroup at all.
|
||||
@@ -131,3 +131,54 @@ run "initctl reload"
|
||||
|
||||
retry 'assert_num_children 1 service.sh'
|
||||
assert_desc "Test service" service.sh
|
||||
|
||||
# The renamed and split settings each have translation logic behind
|
||||
# them, so exercise the ones with a visible effect.
|
||||
# Only the warning differs, service_register() bails before svc_new()
|
||||
# either way, so this asserts the stanza is skipped, not that the
|
||||
# warning was suppressed. The emitted one-liner is where nowarn is
|
||||
# visible, with finit.debug=on.
|
||||
say 'A leading - on command tolerates a missing binary'
|
||||
run "echo 'service ghost {' > $FINIT_CONF"
|
||||
run "echo ' description = \"Ghost\"' >> $FINIT_CONF"
|
||||
run "echo ' command = \"-/no/such/binary\"' >> $FINIT_CONF"
|
||||
run "echo '}' >> $FINIT_CONF"
|
||||
run "initctl reload"
|
||||
|
||||
assert_num_services 0 ghost
|
||||
|
||||
say 'exec-start-pre runs before the service, pidfile-create makes Finit own the file'
|
||||
run "echo 'service service.sh {' > $FINIT_CONF"
|
||||
run "echo ' description = \"Test service\"' >> $FINIT_CONF"
|
||||
run "echo ' conditions = { \"hook/svc/up\" }' >> $FINIT_CONF"
|
||||
run "echo ' exec-start-pre = \"/bin/pre.sh\"' >> $FINIT_CONF"
|
||||
run "echo ' exec-start-pre-timeout = 5' >> $FINIT_CONF"
|
||||
run "echo ' pidfile = \"/run/blockfmt.pid\"' >> $FINIT_CONF"
|
||||
run "echo ' pidfile-create = true' >> $FINIT_CONF"
|
||||
run "echo ' restart = true' >> $FINIT_CONF"
|
||||
run "echo ' restart-max = 3' >> $FINIT_CONF"
|
||||
run "echo ' command = \"service.sh\"' >> $FINIT_CONF"
|
||||
run "echo '}' >> $FINIT_CONF"
|
||||
run "initctl reload"
|
||||
|
||||
retry 'assert_num_children 1 service.sh'
|
||||
retry 'assert_file_exists /tmp/pre'
|
||||
assert_restart_cnt 0 "0/3" service.sh
|
||||
|
||||
# service.sh writes /run/service.pid, never /run/blockfmt.pid, so only
|
||||
# Finit can have created this one. assert_is_pidfile cannot tell, it
|
||||
# prints the path with any leading ! stripped.
|
||||
retry 'assert_file_exists /run/blockfmt.pid'
|
||||
|
||||
say 'Without pidfile-create the daemon owns the file, Finit does not make it'
|
||||
run "echo 'service service.sh {' > $FINIT_CONF"
|
||||
run "echo ' description = \"Test service\"' >> $FINIT_CONF"
|
||||
run "echo ' pidfile = \"/run/notmine.pid\"' >> $FINIT_CONF"
|
||||
run "echo ' command = \"service.sh\"' >> $FINIT_CONF"
|
||||
run "echo '}' >> $FINIT_CONF"
|
||||
run "rm -f /run/notmine.pid"
|
||||
run "initctl reload"
|
||||
|
||||
retry 'assert_num_children 1 service.sh'
|
||||
assert "daemon-owned pidfile is not created by Finit" \
|
||||
"$(texec ls /run/notmine.pid 2>/dev/null)" = ""
|
||||
|
||||
@@ -25,7 +25,7 @@ test_teardown()
|
||||
say 'Install a block-format template'
|
||||
run "echo 'service serv:%i {' > $FINIT_RCSD/available/serv@.conf"
|
||||
run "echo ' description = \"Template for %i\"' >> $FINIT_RCSD/available/serv@.conf"
|
||||
run "echo ' pid = \"/run/serv-%i.pid\"' >> $FINIT_RCSD/available/serv@.conf"
|
||||
run "echo ' pidfile = \"/run/serv-%i.pid\"' >> $FINIT_RCSD/available/serv@.conf"
|
||||
run "echo ' command = \"serv -n -p -P /run/serv-%i.pid\"' >> $FINIT_RCSD/available/serv@.conf"
|
||||
run "echo '}' >> $FINIT_RCSD/available/serv@.conf"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user