mirror of
https://github.com/troglobit/finit.git
synced 2026-11-13 17:00:16 +00:00
service: don't take a command named like an option for one
A run/task/service whose command starts like an option without a ':'
lost its command, e.g. the example in finit.conf(5):
run [2345] @joe:users logger "Hello world"
was registered as the log option, running "Hello world". Same for
pidof, pidproxy, cgroupfs-mount, and in block format too.
The option parser matches with MATCH_CMD(), a prefix match, also for
the options with no trailing ':' to end the prefix: log, pid, cgroup,
respawn, nowarn, and the rest.
Match these against the whole token, allowing only the separator that
starts a value: "log:", "pid:", "cgroup." and "cgroup:".
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This commit is contained in:
3 files changed
+44
-9
No files matched your search
@@ -156,6 +156,9 @@ All relevant changes are documented in this file.
|
|||||||
- Fix #512: `--` in the `command` of a block-format .conf, it was taken as the
|
- Fix #512: `--` in the `command` of a block-format .conf, it was taken as the
|
||||||
start of the description, so `command = "cmd -- arg"` ran `cmd` with
|
start of the description, so `command = "cmd -- arg"` ran `cmd` with
|
||||||
description `arg`. Found by Alexandru Paniș
|
description `arg`. Found by Alexandru Paniș
|
||||||
|
- Fix a command whose name starts like a service option, e.g. `logger` or
|
||||||
|
`pidof`. It was taken as the `log` or `pid` option and the next argument
|
||||||
|
ran as the command, which also broke the `logger` example in finit.conf(5)
|
||||||
- Reject a .conf file that declares the same block title twice. The title is
|
- Reject a .conf file that declares the same block title twice. The title is
|
||||||
the service identity and libConfuse merges two sections sharing one, so the
|
the service identity and libConfuse merges two sections sharing one, so the
|
||||||
file loaded as a single service holding a mix of both declarations,
|
file loaded as a single service holding a mix of both declarations,
|
||||||
|
|||||||
+31
-9
@@ -1812,6 +1812,24 @@ static char *parse_args(char **line)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Match an option that takes a value, @opt on its own or followed by
|
||||||
|
* one of the characters in @sep, e.g. "log" and "log:/path". Returns
|
||||||
|
* the value, or NULL, so a command like logger or pidof is not taken
|
||||||
|
* for an option.
|
||||||
|
*/
|
||||||
|
static char *is_opt(char *tok, const char *opt, const char *sep)
|
||||||
|
{
|
||||||
|
size_t len = strlen(opt);
|
||||||
|
|
||||||
|
if (strncasecmp(tok, opt, len))
|
||||||
|
return NULL;
|
||||||
|
if (tok[len] && !strchr(sep, tok[len]))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return &tok[len];
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* log:/path/to/logfile,priority:facility.level,tag:ident
|
* log:/path/to/logfile,priority:facility.level,tag:ident
|
||||||
*/
|
*/
|
||||||
@@ -2265,6 +2283,10 @@ svc_t *service_register_desc(int type, char *cfg, const char *desc,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Options ending in ':' can be prefix matched, the rest must match
|
||||||
|
* the whole token or a command like logger is taken for one.
|
||||||
|
*/
|
||||||
while (cmd) {
|
while (cmd) {
|
||||||
char *arg;
|
char *arg;
|
||||||
|
|
||||||
@@ -2279,19 +2301,19 @@ svc_t *service_register_desc(int type, char *cfg, const char *desc,
|
|||||||
cond = &cmd[1];
|
cond = &cmd[1];
|
||||||
else if (cmd[0] == ':') /* :ID */
|
else if (cmd[0] == ':') /* :ID */
|
||||||
id = &cmd[1];
|
id = &cmd[1];
|
||||||
else if (MATCH_CMD(cmd, "log", arg))
|
else if (is_opt(cmd, "log", ":"))
|
||||||
log = cmd;
|
log = cmd;
|
||||||
else if (MATCH_CMD(cmd, "pid", arg))
|
else if (is_opt(cmd, "pid", ":"))
|
||||||
pid = cmd;
|
pid = cmd;
|
||||||
else if (MATCH_CMD(cmd, "name:", arg))
|
else if (MATCH_CMD(cmd, "name:", arg))
|
||||||
name = cmd;
|
name = cmd;
|
||||||
else if (MATCH_CMD(cmd, "notify:", arg))
|
else if (MATCH_CMD(cmd, "notify:", arg))
|
||||||
notify = arg;
|
notify = arg;
|
||||||
else if (MATCH_CMD(cmd, "type:forking", arg))
|
else if (!strcasecmp(cmd, "type:forking"))
|
||||||
forking = 1;
|
forking = 1;
|
||||||
else if (MATCH_CMD(cmd, "manual:yes", arg))
|
else if (!strcasecmp(cmd, "manual:yes"))
|
||||||
manual = 1;
|
manual = 1;
|
||||||
else if (MATCH_CMD(cmd, "remain:yes", arg))
|
else if (!strcasecmp(cmd, "remain:yes"))
|
||||||
remain = 1;
|
remain = 1;
|
||||||
else if (MATCH_CMD(cmd, "restart:", arg)) {
|
else if (MATCH_CMD(cmd, "restart:", arg)) {
|
||||||
if (MATCH_CMD(arg, "always", arg))
|
if (MATCH_CMD(arg, "always", arg))
|
||||||
@@ -2303,9 +2325,9 @@ svc_t *service_register_desc(int type, char *cfg, const char *desc,
|
|||||||
restart_tmo = atoi(arg) * 1000;
|
restart_tmo = atoi(arg) * 1000;
|
||||||
else if (MATCH_CMD(cmd, "restart_sec:", arg))
|
else if (MATCH_CMD(cmd, "restart_sec:", arg))
|
||||||
restart_tmo = atoi(arg) * 1000;
|
restart_tmo = atoi(arg) * 1000;
|
||||||
else if (MATCH_CMD(cmd, "norestart", arg))
|
else if (!strcasecmp(cmd, "norestart"))
|
||||||
restart_max = 0;
|
restart_max = 0;
|
||||||
else if (MATCH_CMD(cmd, "nowarn", arg))
|
else if (!strcasecmp(cmd, "nowarn"))
|
||||||
nowarn = 1;
|
nowarn = 1;
|
||||||
else if (MATCH_CMD(cmd, "oncrash:", arg)) {
|
else if (MATCH_CMD(cmd, "oncrash:", arg)) {
|
||||||
if (MATCH_CMD(arg, "reboot", arg))
|
if (MATCH_CMD(arg, "reboot", arg))
|
||||||
@@ -2313,7 +2335,7 @@ svc_t *service_register_desc(int type, char *cfg, const char *desc,
|
|||||||
if (MATCH_CMD(arg, "script", arg))
|
if (MATCH_CMD(arg, "script", arg))
|
||||||
oncrash_action = SVC_ONCRASH_SCRIPT;
|
oncrash_action = SVC_ONCRASH_SCRIPT;
|
||||||
}
|
}
|
||||||
else if (MATCH_CMD(cmd, "respawn", arg))
|
else if (!strcasecmp(cmd, "respawn"))
|
||||||
respawn = 1;
|
respawn = 1;
|
||||||
else if (MATCH_CMD(cmd, "halt:", arg))
|
else if (MATCH_CMD(cmd, "halt:", arg))
|
||||||
halt = arg;
|
halt = arg;
|
||||||
@@ -2338,7 +2360,7 @@ svc_t *service_register_desc(int type, char *cfg, const char *desc,
|
|||||||
else if (MATCH_CMD(cmd, "tty:", arg))
|
else if (MATCH_CMD(cmd, "tty:", arg))
|
||||||
ctty = arg;
|
ctty = arg;
|
||||||
/* catch both cgroup: and cgroup. handled in parse_cgroup() */
|
/* catch both cgroup: and cgroup. handled in parse_cgroup() */
|
||||||
else if (MATCH_CMD(cmd, "cgroup", arg))
|
else if ((arg = is_opt(cmd, "cgroup", ".:")))
|
||||||
cgroup = arg;
|
cgroup = arg;
|
||||||
else if (MATCH_CMD(cmd, "conflict:", arg))
|
else if (MATCH_CMD(cmd, "conflict:", arg))
|
||||||
conflict = arg;
|
conflict = arg;
|
||||||
|
|||||||
@@ -89,6 +89,16 @@ retry 'assert_cmd pick "serv -np -i pick -- extra"'
|
|||||||
assert_desc "Dashes" pick
|
assert_desc "Dashes" pick
|
||||||
assert_num_children 1 serv
|
assert_num_children 1 serv
|
||||||
|
|
||||||
|
# Options are matched as whole tokens, so a command that merely starts
|
||||||
|
# like one, pidof vs. pid, is still the command.
|
||||||
|
say 'A command named like an option is the command'
|
||||||
|
run "echo 'task lookalike {' > $FINIT_CONF"
|
||||||
|
run "echo ' command = \"pidof serv\"' >> $FINIT_CONF"
|
||||||
|
run "echo '}' >> $FINIT_CONF"
|
||||||
|
run "initctl reload"
|
||||||
|
|
||||||
|
retry 'assert_cmd lookalike "pidof serv"'
|
||||||
|
|
||||||
# A tty block takes the same list, its command is the getty to run.
|
# A tty block takes the same list, its command is the getty to run.
|
||||||
# Asserting it is loaded is enough here, a getty in the test namespace
|
# Asserting it is loaded is enough here, a getty in the test namespace
|
||||||
# has no terminal to attach to.
|
# has no terminal to attach to.
|
||||||
|
|||||||
Reference in new issue
Block a user