mirror of
https://github.com/troglobit/finit.git
synced 2026-11-03 13:28:27 +00:00
Fix #155: add support for env:/a/bc to service/run/task
This patch makes it possible to create a service with optional
arguments, similar to the systemd EnvironmentFile= setting.
The major difference to systemd, is that Finit does not attempt
to start a service if it cannot find the env. file, unless it
is prefixed with '-'.
Example:
/etc/default/syslogd:
SYSLOGD_OPTS="-m0 -r 128k:10 -s"
/etc/finit.d/enabled/syslogd.conf
service env:-/etc/default/syslogd syslogd -F $SYSLOGD_OPTS
Only downside, right now, is that changing the contents of the file
/etc/default/syslogd does not mark the syslogd.conf as modified and
a subsequent `initctl reload` will *not* restart syslogd.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This commit is contained in:
1 parent
fc82f0242c
commit
f4a0b99df8
3 files changed
+187
-13
No files matched your search
@@ -494,6 +494,7 @@ static int show_status(char *arg)
|
|||||||
printf("Service : %s\n", svc->cmd);
|
printf("Service : %s\n", svc->cmd);
|
||||||
printf("Description : %s\n", svc->desc);
|
printf("Description : %s\n", svc->desc);
|
||||||
printf("Identity : %s\n", svc_ident(svc, ident, sizeof(ident)));
|
printf("Identity : %s\n", svc_ident(svc, ident, sizeof(ident)));
|
||||||
|
printf("Environment : %s\n", svc->env);
|
||||||
printf("PID : %d\n", svc->pid);
|
printf("PID : %d\n", svc->pid);
|
||||||
printf("Uptime : %s\n", svc->pid ? uptime(now - svc->start_time, buf, sizeof(buf)) : buf);
|
printf("Uptime : %s\n", svc->pid ? uptime(now - svc->start_time, buf, sizeof(buf)) : buf);
|
||||||
printf("Runlevels : %s\n", runlevel_string(runlevel, svc->runlevels));
|
printf("Runlevels : %s\n", runlevel_string(runlevel, svc->runlevels));
|
||||||
|
|||||||
+185
-13
@@ -32,6 +32,7 @@
|
|||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <net/if.h>
|
#include <net/if.h>
|
||||||
#include <lite/lite.h>
|
#include <lite/lite.h>
|
||||||
|
#include <wordexp.h>
|
||||||
|
|
||||||
#include "cgroup.h"
|
#include "cgroup.h"
|
||||||
#include "conf.h"
|
#include "conf.h"
|
||||||
@@ -261,6 +262,121 @@ static int redirect(svc_t *svc)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* non-zero env, no checking if file exists or not
|
||||||
|
*/
|
||||||
|
static char *svc_getenv(svc_t *svc)
|
||||||
|
{
|
||||||
|
int v = 0;
|
||||||
|
|
||||||
|
if (!svc->env[0])
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (svc->env[0] == '-')
|
||||||
|
v = 1;
|
||||||
|
|
||||||
|
return &svc->env[v];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if svc has env, if env file exists returns true
|
||||||
|
* if it doesn't exist, but has '-', also true. if svc
|
||||||
|
* doesn't have env, also true.
|
||||||
|
*/
|
||||||
|
static int check_env(svc_t *svc)
|
||||||
|
{
|
||||||
|
char *env = svc_getenv(svc);
|
||||||
|
|
||||||
|
if (!env)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return fexist(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Source environment file, if it exists
|
||||||
|
* Note: must be called from privsepped child
|
||||||
|
*/
|
||||||
|
static void source_env(svc_t *svc)
|
||||||
|
{
|
||||||
|
char buf[LINE_SIZE];
|
||||||
|
char *line;
|
||||||
|
size_t len;
|
||||||
|
FILE *fp;
|
||||||
|
char *fn;
|
||||||
|
|
||||||
|
fn = svc_getenv(svc);
|
||||||
|
if (!fn)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Warning in service_start() after check_env() */
|
||||||
|
fp = fopen(fn, "r");
|
||||||
|
if (!fp)
|
||||||
|
return;
|
||||||
|
|
||||||
|
line = buf;
|
||||||
|
len = sizeof(buf);
|
||||||
|
while (fgets(line, len, fp)) {
|
||||||
|
char *key = chomp(line);
|
||||||
|
char *value, *end;
|
||||||
|
|
||||||
|
/* skip any leading whitespace */
|
||||||
|
while (isspace(*key))
|
||||||
|
key++;
|
||||||
|
|
||||||
|
/* skip comments */
|
||||||
|
if (*key == '#' || *key == ';')
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* find end of line */
|
||||||
|
end = key;
|
||||||
|
while (*end)
|
||||||
|
end++;
|
||||||
|
|
||||||
|
/* strip trailing whitespace */
|
||||||
|
if (end > key) {
|
||||||
|
end--;
|
||||||
|
while (isspace(*end))
|
||||||
|
*end-- = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
value = strchr(key, '=');
|
||||||
|
if (!value)
|
||||||
|
continue;
|
||||||
|
*value++ = 0;
|
||||||
|
|
||||||
|
/* strip leading whitespace from value */
|
||||||
|
while (isspace(*value))
|
||||||
|
value++;
|
||||||
|
|
||||||
|
/* unquote value, if quoted */
|
||||||
|
if (value[0] == '"' || value[0] == '\'') {
|
||||||
|
char q = value[0];
|
||||||
|
|
||||||
|
if (*end == q) {
|
||||||
|
value = &value[1];
|
||||||
|
*end = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* find end of key */
|
||||||
|
end = key;
|
||||||
|
while (*end)
|
||||||
|
end++;
|
||||||
|
|
||||||
|
/* strip trailing whitespace */
|
||||||
|
if (end > key) {
|
||||||
|
end--;
|
||||||
|
while (isspace(*end))
|
||||||
|
*end-- = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
setenv(key, value, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
|
||||||
static int is_norespawn(void)
|
static int is_norespawn(void)
|
||||||
{
|
{
|
||||||
return sig_stopped() ||
|
return sig_stopped() ||
|
||||||
@@ -277,9 +393,10 @@ static int is_norespawn(void)
|
|||||||
*/
|
*/
|
||||||
static int service_start(svc_t *svc)
|
static int service_start(svc_t *svc)
|
||||||
{
|
{
|
||||||
int i, result = 0, do_progress = 1;
|
int result = 0, do_progress = 1;
|
||||||
pid_t pid;
|
|
||||||
sigset_t nmask, omask;
|
sigset_t nmask, omask;
|
||||||
|
pid_t pid;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
if (!svc)
|
if (!svc)
|
||||||
return 1;
|
return 1;
|
||||||
@@ -290,11 +407,17 @@ static int service_start(svc_t *svc)
|
|||||||
|
|
||||||
/* Don't try and start service if it doesn't exist. */
|
/* Don't try and start service if it doesn't exist. */
|
||||||
if (!whichp(svc->cmd)) {
|
if (!whichp(svc->cmd)) {
|
||||||
print(1, "Service %s does not exist", svc->cmd);
|
print(1, "%s: does not exist", svc->cmd);
|
||||||
svc_missing(svc);
|
svc_missing(svc);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Unlike systemd we do not allow starting service if env is missing, unless - */
|
||||||
|
if (!check_env(svc)) {
|
||||||
|
print(1, "%s: environment file %s does not exist (yet)", svc->cmd, svc->env);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (svc_is_sysv(svc))
|
if (svc_is_sysv(svc))
|
||||||
logit(LOG_CONSOLE | LOG_NOTICE, "Calling '%s start' ...", svc->cmd);
|
logit(LOG_CONSOLE | LOG_NOTICE, "Calling '%s start' ...", svc->cmd);
|
||||||
|
|
||||||
@@ -355,12 +478,45 @@ static int service_start(svc_t *svc)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Source any environment from env:/path/to/file */
|
||||||
|
source_env(svc);
|
||||||
|
|
||||||
if (!svc_is_sysv(svc)) {
|
if (!svc_is_sysv(svc)) {
|
||||||
|
wordexp_t we = { 0 };
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if ((rc = wordexp(svc->cmd, &we, 0))) {
|
||||||
|
nomem:
|
||||||
|
_e("%s: failed wordexp(): %d", svc->cmd, rc);
|
||||||
|
wordfree(&we);
|
||||||
|
_exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < MAX_NUM_SVC_ARGS; i++) {
|
for (i = 0; i < MAX_NUM_SVC_ARGS; i++) {
|
||||||
if (strlen(svc->args[i]) == 0)
|
if (strlen(svc->args[i]) == 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
if ((rc = wordexp(svc->args[i], &we, WRDE_APPEND)))
|
||||||
|
goto nomem;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (we.we_wordc > MAX_NUM_SVC_ARGS) {
|
||||||
|
logit(LOG_ERR, "%s: too man args after expansion.", svc->cmd);
|
||||||
|
goto nomem;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < we.we_wordc; i++) {
|
||||||
|
if (strlen(we.we_wordv[i]) >= sizeof(svc->args[i])) {
|
||||||
|
logit(LOG_ERR, "%s: expanded arg. '%s' too long", we.we_wordv[i]);
|
||||||
|
rc = WRDE_NOSPACE;
|
||||||
|
goto nomem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* overwrite the child's svc with expanded args */
|
||||||
|
strlcpy(svc->args[i], we.we_wordv[i], sizeof(svc->args[i]));
|
||||||
args[i] = svc->args[i];
|
args[i] = svc->args[i];
|
||||||
}
|
}
|
||||||
|
wordfree(&we);
|
||||||
} else {
|
} else {
|
||||||
i = 0;
|
i = 0;
|
||||||
args[i++] = svc->cmd;
|
args[i++] = svc->cmd;
|
||||||
@@ -372,12 +528,11 @@ static int service_start(svc_t *svc)
|
|||||||
sig_unblock();
|
sig_unblock();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The setsid() call is the most humble of all in this
|
* The setsid() call takes care to detach the process
|
||||||
* function. It takes care to detach the process from
|
* from its controlling terminal, preventing daemons
|
||||||
* its controlling terminal, preventing daemons from
|
* from leaking to the console, and allowing us to run
|
||||||
* leaking to the console, and allowing us to run such
|
* such programs like `lxc-start -F` in the foreground
|
||||||
* programs like `lxc-start -F` in the foreground to
|
* to properly monitor them.
|
||||||
* properly monitor them.
|
|
||||||
*
|
*
|
||||||
* If you find yourself here wanting to fix the output
|
* If you find yourself here wanting to fix the output
|
||||||
* to the console at boot, for debugging or similar,
|
* to the console at boot, for debugging or similar,
|
||||||
@@ -386,9 +541,9 @@ static int service_start(svc_t *svc)
|
|||||||
setsid();
|
setsid();
|
||||||
|
|
||||||
if (svc_is_runtask(svc))
|
if (svc_is_runtask(svc))
|
||||||
status = exec_runtask(svc->cmd, args);
|
status = exec_runtask(args[0], &args[1]);
|
||||||
else
|
else
|
||||||
status = execvp(svc->cmd, args);
|
status = execvp(args[0], &args[1]);
|
||||||
|
|
||||||
_exit(status);
|
_exit(status);
|
||||||
} else if (debug) {
|
} else if (debug) {
|
||||||
@@ -396,7 +551,7 @@ static int service_start(svc_t *svc)
|
|||||||
|
|
||||||
for (i = 0; i < MAX_NUM_SVC_ARGS; i++) {
|
for (i = 0; i < MAX_NUM_SVC_ARGS; i++) {
|
||||||
if (strlen(svc->args[i]) == 0)
|
if (strlen(svc->args[i]) == 0)
|
||||||
continue;
|
break;
|
||||||
if (buf[0])
|
if (buf[0])
|
||||||
strlcat(buf, " ", sizeof(buf));
|
strlcat(buf, " ", sizeof(buf));
|
||||||
strlcat(buf, svc->args[i], sizeof(buf));
|
strlcat(buf, svc->args[i], sizeof(buf));
|
||||||
@@ -661,6 +816,19 @@ static void parse_log(svc_t *svc, char *arg)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void parse_env(svc_t *svc, char *env)
|
||||||
|
{
|
||||||
|
if (!env)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (strlen(env) >= sizeof(svc->env)) {
|
||||||
|
_e("%s: env file is too long (>%d chars)", svc->cmd, sizeof(svc->env));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
strlcpy(svc->env, env, sizeof(svc->env));
|
||||||
|
}
|
||||||
|
|
||||||
static void parse_sighalt(svc_t *svc, char *arg)
|
static void parse_sighalt(svc_t *svc, char *arg)
|
||||||
{
|
{
|
||||||
int signo;
|
int signo;
|
||||||
@@ -798,7 +966,7 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
|
|||||||
char *cmd, *desc, *runlevels = NULL, *cond = NULL;
|
char *cmd, *desc, *runlevels = NULL, *cond = NULL;
|
||||||
char *username = NULL, *log = NULL, *pid = NULL;
|
char *username = NULL, *log = NULL, *pid = NULL;
|
||||||
char *name = NULL, *halt = NULL, *delay = NULL;
|
char *name = NULL, *halt = NULL, *delay = NULL;
|
||||||
char *id = NULL;
|
char *id = NULL, *env = NULL;
|
||||||
int levels = 0;
|
int levels = 0;
|
||||||
int manual = 0;
|
int manual = 0;
|
||||||
char *line;
|
char *line;
|
||||||
@@ -860,6 +1028,8 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
|
|||||||
halt = &cmd[5];
|
halt = &cmd[5];
|
||||||
else if (!strncasecmp(cmd, "kill:", 5))
|
else if (!strncasecmp(cmd, "kill:", 5))
|
||||||
delay = &cmd[5];
|
delay = &cmd[5];
|
||||||
|
else if (!strncasecmp(cmd, "env:", 4))
|
||||||
|
env = &cmd[4];
|
||||||
else
|
else
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -925,6 +1095,8 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
|
|||||||
parse_log(svc, log);
|
parse_log(svc, log);
|
||||||
if (desc)
|
if (desc)
|
||||||
strlcpy(svc->desc, desc, sizeof(svc->desc));
|
strlcpy(svc->desc, desc, sizeof(svc->desc));
|
||||||
|
if (env)
|
||||||
|
parse_env(svc, env);
|
||||||
|
|
||||||
/* Set configured limits */
|
/* Set configured limits */
|
||||||
memcpy(svc->rlimit, rlimit, sizeof(svc->rlimit));
|
memcpy(svc->rlimit, rlimit, sizeof(svc->rlimit));
|
||||||
|
|||||||
@@ -134,6 +134,7 @@ typedef struct svc {
|
|||||||
char cmd[MAX_ARG_LEN];
|
char cmd[MAX_ARG_LEN];
|
||||||
char args[MAX_NUM_SVC_ARGS][MAX_ARG_LEN];
|
char args[MAX_NUM_SVC_ARGS][MAX_ARG_LEN];
|
||||||
char desc[MAX_STR_LEN];
|
char desc[MAX_STR_LEN];
|
||||||
|
char env[MAX_ARG_LEN];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Used to forcefully kill services that won't shutdown on
|
* Used to forcefully kill services that won't shutdown on
|
||||||
|
|||||||
Reference in new issue
Block a user