Add support for setting environment variables from finit.conf

Finit can now track and set environment variables from finit.conf.  The
syntax is pretty much what you'd expect:

    foo=bar
    baz="qux"

On reload of .conf files, all tracked environment variables are cleared
so if `foo=bar` is removed from finit.conf, or any finit.d/*.conf file,
it will no longer be used by Finit or any new (!) started run/tasks or
services.

The only variables reset to sane defaults on .conf reload are:

    PATH=_PATH_STDPATH
    SHELL=_PATH_BSHELL
    LOGNAME=root
    USER=root

It is entirely possible to override these as well from the .conf files,
but be careful.  Changing SHELL changes the behavior of system() and a
lot of other commands as well.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This commit is contained in:
Joachim Wiberg committed 2022-05-02 00:02:44 +02:00
1 parent bf62bee440
commit 38db52aa4e
3 files changed
+135 -28

No files matched your search

+133 -24
View File
@@ -54,6 +54,12 @@
int logfile_size_max = 200000; /* 200 kB */ int logfile_size_max = 200000; /* 200 kB */
int logfile_count_max = 5; int logfile_count_max = 5;
struct env_entry {
TAILQ_ENTRY(env_entry) link;
char *name;
};
static TAILQ_HEAD(, env_entry) env_list = TAILQ_HEAD_INITIALIZER(env_list);
struct rlimit initial_rlimit[RLIMIT_NLIMITS]; struct rlimit initial_rlimit[RLIMIT_NLIMITS];
struct rlimit global_rlimit[RLIMIT_NLIMITS]; struct rlimit global_rlimit[RLIMIT_NLIMITS];
@@ -67,7 +73,7 @@ struct conf_change {
static struct iwatch iw_conf; static struct iwatch iw_conf;
static uev_t etcw; static uev_t etcw;
static TAILQ_HEAD(head, conf_change) conf_change_list = TAILQ_HEAD_INITIALIZER(conf_change_list); static TAILQ_HEAD(, conf_change) conf_change_list = TAILQ_HEAD_INITIALIZER(conf_change_list);
static int parse_conf(char *file, int is_rcsd); static int parse_conf(char *file, int is_rcsd);
static void drop_changes(void); static void drop_changes(void);
@@ -213,6 +219,98 @@ void conf_parse_cmdline(int argc, char *argv[])
parse_kernel_loglevel(); parse_kernel_loglevel();
} }
/*
* Clear all environment variables read in parse_env(), they may be
* removed now so let the next call to parse_env() restore them.
*/
void conf_reset_env(void)
{
struct env_entry *node, *tmp;
TAILQ_FOREACH_SAFE(node, &env_list, link, tmp) {
TAILQ_REMOVE(&env_list, node, link);
if (node->name) {
unsetenv(node->name);
free(node->name);
}
free(node);
}
setenv("PATH", _PATH_STDPATH, 1);
setenv("SHELL", _PATH_BSHELL, 1);
setenv("LOGNAME", "root", 1);
setenv("USER", "root", 1);
}
/*
* Sets, and makes a note of, all KEY=VALUE lines in a given .conf line
* from finit.conf, or other .conf file. Note, PATH is always reset in
* the conf_reset_env() function.
*/
static void parse_env(char *line)
{
struct env_entry *node;
char *key, *val, *end;
/* skip any leading whitespace */
key = line;
while (isspace(*key))
key++;
/* find end of line */
end = key;
while (*end)
end++;
/* strip trailing whitespace */
if (end > key) {
end--;
while (isspace(*end))
*end-- = 0;
}
val = strchr(key, '=');
if (!val)
return;
*val++ = 0;
/* strip leading whitespace from value */
while (isspace(*val))
val++;
/* unquote value, if quoted */
if (val[0] == '"' || val[0] == '\'') {
char q = val[0];
if (*end == q) {
val = &val[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, val, 1);
node = malloc(sizeof(*node));
if (!node) {
_pe("Out of memory cannot track env vars");
return;
}
node->name = strdup(key);
TAILQ_INSERT_HEAD(&env_list, node, link);
}
static int kmod_exists(char *mod) static int kmod_exists(char *mod)
{ {
char buf[256]; char buf[256];
@@ -484,7 +582,7 @@ static void conf_parse_cgroup(char *line)
cgroup_add(name, config, 0); cgroup_add(name, config, 0);
} }
static void parse_static(char *line, int is_rcsd) static int parse_static(char *line, int is_rcsd)
{ {
char cmd[CMD_SIZE]; char cmd[CMD_SIZE];
char *x; char *x;
@@ -492,7 +590,7 @@ static void parse_static(char *line, int is_rcsd)
if (BOOTSTRAP && (MATCH_CMD(line, "host ", x) || MATCH_CMD(line, "hostname ", x))) { if (BOOTSTRAP && (MATCH_CMD(line, "host ", x) || MATCH_CMD(line, "hostname ", x))) {
if (hostname) free(hostname); if (hostname) free(hostname);
hostname = strdup(strip_line(x)); hostname = strdup(strip_line(x));
return; return 0;
} }
if (BOOTSTRAP && MATCH_CMD(line, "mknod ", x)) { if (BOOTSTRAP && MATCH_CMD(line, "mknod ", x)) {
@@ -501,25 +599,25 @@ static void parse_static(char *line, int is_rcsd)
strcpy(cmd, "mknod "); strcpy(cmd, "mknod ");
strlcat(cmd, dev, sizeof(cmd)); strlcat(cmd, dev, sizeof(cmd));
run_interactive(cmd, "Creating device node %s", dev); run_interactive(cmd, "Creating device node %s", dev);
return; return 0;
} }
/* Kernel module to load */ /* Kernel module to load */
if (BOOTSTRAP && MATCH_CMD(line, "module ", x)) { if (BOOTSTRAP && MATCH_CMD(line, "module ", x)) {
kmod_load(strip_line(x)); kmod_load(strip_line(x));
return; return 0;
} }
if (BOOTSTRAP && MATCH_CMD(line, "network ", x)) { if (BOOTSTRAP && MATCH_CMD(line, "network ", x)) {
if (network) free(network); if (network) free(network);
network = strdup(strip_line(x)); network = strdup(strip_line(x));
return; return 0;
} }
if (BOOTSTRAP && MATCH_CMD(line, "runparts ", x)) { if (BOOTSTRAP && MATCH_CMD(line, "runparts ", x)) {
if (runparts) free(runparts); if (runparts) free(runparts);
runparts = strdup(strip_line(x)); runparts = strdup(strip_line(x));
return; return 0;
} }
if (MATCH_CMD(line, "include ", x)) { if (MATCH_CMD(line, "include ", x)) {
@@ -528,11 +626,10 @@ static void parse_static(char *line, int is_rcsd)
strlcpy(cmd, file, sizeof(cmd)); strlcpy(cmd, file, sizeof(cmd));
if (!fexist(cmd)) { if (!fexist(cmd)) {
_e("Cannot find include file %s, absolute path required!", x); _e("Cannot find include file %s, absolute path required!", x);
return; return 1;
} }
parse_conf(cmd, is_rcsd); return parse_conf(cmd, is_rcsd);
return;
} }
if (MATCH_CMD(line, "log ", x)) { if (MATCH_CMD(line, "log ", x)) {
@@ -553,12 +650,14 @@ static void parse_static(char *line, int is_rcsd)
logfile_size_max = size; logfile_size_max = size;
if (count >= 0) if (count >= 0)
logfile_count_max = count; logfile_count_max = count;
return 0;
} }
if (MATCH_CMD(line, "shutdown ", x)) { if (MATCH_CMD(line, "shutdown ", x)) {
if (sdown) free(sdown); if (sdown) free(sdown);
sdown = strdup(strip_line(x)); sdown = strdup(strip_line(x));
return; return 0;
} }
/* /*
@@ -575,7 +674,7 @@ static void parse_static(char *line, int is_rcsd)
cfglevel = RUNLEVEL; cfglevel = RUNLEVEL;
if (cfglevel < 1 || cfglevel > 9 || cfglevel == 6) if (cfglevel < 1 || cfglevel > 9 || cfglevel == 6)
cfglevel = 2; /* Fallback */ cfglevel = 2; /* Fallback */
return; return 0;
} }
/* /*
@@ -595,61 +694,65 @@ static void parse_static(char *line, int is_rcsd)
if (disabled) if (disabled)
service_init(); service_init();
} }
return; return 0;
} }
return 1;
} }
static void parse_dynamic(char *line, struct rlimit rlimit[], char *file) static int parse_dynamic(char *line, struct rlimit rlimit[], char *file)
{ {
char *x; char *x;
/* Monitored daemon, will be respawned on exit */ /* Monitored daemon, will be respawned on exit */
if (MATCH_CMD(line, "service ", x)) { if (MATCH_CMD(line, "service ", x)) {
service_register(SVC_TYPE_SERVICE, x, rlimit, file); service_register(SVC_TYPE_SERVICE, x, rlimit, file);
return; return 0;
} }
/* One-shot task, will not be respawned */ /* One-shot task, will not be respawned */
if (MATCH_CMD(line, "task ", x)) { if (MATCH_CMD(line, "task ", x)) {
service_register(SVC_TYPE_TASK, x, rlimit, file); service_register(SVC_TYPE_TASK, x, rlimit, file);
return; return 0;
} }
/* Like task but waits for completion, useful w/ [S] */ /* Like task but waits for completion, useful w/ [S] */
if (MATCH_CMD(line, "run ", x)) { if (MATCH_CMD(line, "run ", x)) {
service_register(SVC_TYPE_RUN, x, rlimit, file); service_register(SVC_TYPE_RUN, x, rlimit, file);
return; return 0;
} }
/* Similar to task but is treated like a SysV init script */ /* Similar to task but is treated like a SysV init script */
if (MATCH_CMD(line, "sysv ", x)) { if (MATCH_CMD(line, "sysv ", x)) {
service_register(SVC_TYPE_SYSV, x, rlimit, file); service_register(SVC_TYPE_SYSV, x, rlimit, file);
return; return 0;
} }
/* Read resource limits */ /* Read resource limits */
if (MATCH_CMD(line, "rlimit ", x)) { if (MATCH_CMD(line, "rlimit ", x)) {
conf_parse_rlimit(x, rlimit); conf_parse_rlimit(x, rlimit);
return; return 0;
} }
/* Read control group limits */ /* Read control group limits */
if (MATCH_CMD(line, "cgroup ", x)) { if (MATCH_CMD(line, "cgroup ", x)) {
conf_parse_cgroup(x); conf_parse_cgroup(x);
return; return 0;
} }
/* Set current cgroup for the following services/run/tasks */ /* Set current cgroup for the following services/run/tasks */
if (MATCH_CMD(line, "cgroup.", x)) { if (MATCH_CMD(line, "cgroup.", x)) {
strlcpy(cgroup_current, x, sizeof(cgroup_current)); strlcpy(cgroup_current, x, sizeof(cgroup_current));
return; return 0;
} }
/* Regular or serial TTYs to run getty */ /* Regular or serial TTYs to run getty */
if (MATCH_CMD(line, "tty ", x)) { if (MATCH_CMD(line, "tty ", x)) {
service_register(SVC_TYPE_TTY, strip_line(x), rlimit, file); service_register(SVC_TYPE_TTY, strip_line(x), rlimit, file);
return; return 0;
} }
return 1;
} }
static void tabstospaces(char *line) static void tabstospaces(char *line)
@@ -694,8 +797,13 @@ static int parse_conf(char *file, int is_rcsd)
if (MATCH_CMD(line, "#", x)) if (MATCH_CMD(line, "#", x))
continue; continue;
parse_static(line, is_rcsd); if (!parse_static(line, is_rcsd))
parse_dynamic(line, is_rcsd ? rlimit : global_rlimit, file); continue;
if (!parse_dynamic(line, is_rcsd ? rlimit : global_rlimit, file))
continue;
/* Not static or dynamic conf, check if it is a global env. */
parse_env(line);
} }
fclose(fp); fclose(fp);
@@ -719,6 +827,7 @@ int conf_reload(void)
/* Mark and sweep */ /* Mark and sweep */
cgroup_mark_all(); cgroup_mark_all();
svc_mark_dynamic(); svc_mark_dynamic();
conf_reset_env();
/* /*
* Reset global rlimit to bootstrap values from conf_init(). * Reset global rlimit to bootstrap values from conf_init().
+1
View File
@@ -42,6 +42,7 @@ int conf_any_change (void);
int conf_changed (char *file); int conf_changed (char *file);
int conf_monitor (void); int conf_monitor (void);
void conf_reset_env (void);
void conf_parse_cmdline (int argc, char *argv[]); void conf_parse_cmdline (int argc, char *argv[]);
int conf_parse_runlevels (char *runlevels); int conf_parse_runlevels (char *runlevels);
void conf_parse_cond (svc_t *svc, char *cond); void conf_parse_cond (svc_t *svc, char *cond);
+1 -4
View File
@@ -729,10 +729,7 @@ int main(int argc, char *argv[])
/* /*
* Set PATH, SHELL, and PWD early to something sane * Set PATH, SHELL, and PWD early to something sane
*/ */
setenv("PATH", _PATH_STDPATH, 1); conf_reset_env();
setenv("SHELL", _PATH_BSHELL, 1);
setenv("LOGNAME", "root", 1);
setenv("USER", "root", 1);
if (chdir("/")) if (chdir("/"))
_pe("Failed cd /"); _pe("Failed cd /");