Merge pull request #10059 from yuwata/env-exec-directory
core: introduce $RUNTIME_DIRECTORY= or friends
This commit is contained in:
commit
7c428bb5d5
9
TODO
9
TODO
|
@ -249,15 +249,6 @@ Features:
|
|||
for all units. It should be both a way to pin units into memory as well as a
|
||||
wait to retrieve their exit data.
|
||||
|
||||
* maybe set a new set of env vars for services, based on RuntimeDirectory=,
|
||||
StateDirectory=, LogsDirectory=, CacheDirectory= and ConfigurationDirectory=
|
||||
automatically. For example, there could be $RUNTIME_DIRECTORY,
|
||||
$STATE_DIRECTORY, $LOGS_DIRECTORY=, $CACHE_DIRECTORY and
|
||||
$CONFIGURATION_DIRECTORY or so. This could be useful to write services that
|
||||
can adapt to varying directories for these purposes. Special care has to be
|
||||
taken if multiple dirs are configured. Maybe avoid setting the env vars in
|
||||
that case?
|
||||
|
||||
* expose IO accounting data on the bus, show it in systemd-run --wait and log
|
||||
about it in the resource log message
|
||||
|
||||
|
|
|
@ -814,15 +814,18 @@ CapabilityBoundingSet=~CAP_B CAP_C</programlisting>
|
|||
<listitem><para>These options take a whitespace-separated list of directory names. The specified directory
|
||||
names must be relative, and may not include <literal>..</literal>. If set, one or more
|
||||
directories by the specified names will be created (including their parents) below the locations
|
||||
defined in the following table, when the unit is started.</para>
|
||||
defined in the following table, when the unit is started. Also, the corresponding environment variable
|
||||
is defined with the full path of directories. If multiple directories are set, then int the environment variable
|
||||
the paths are concatenated with colon (<literal>:</literal>).</para>
|
||||
<table>
|
||||
<title>Automatic directory creation</title>
|
||||
<tgroup cols='3'>
|
||||
<title>Automatic directory creation and environment variables</title>
|
||||
<tgroup cols='4'>
|
||||
<thead>
|
||||
<row>
|
||||
<entry>Locations</entry>
|
||||
<entry>for system</entry>
|
||||
<entry>for users</entry>
|
||||
<entry>Environment variable</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
@ -830,26 +833,31 @@ CapabilityBoundingSet=~CAP_B CAP_C</programlisting>
|
|||
<entry><varname>RuntimeDirectory=</varname></entry>
|
||||
<entry><filename>/run</filename></entry>
|
||||
<entry><varname>$XDG_RUNTIME_DIR</varname></entry>
|
||||
<entry><varname>$RUNTIME_DIRECTORY</varname></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><varname>StateDirectory=</varname></entry>
|
||||
<entry><filename>/var/lib</filename></entry>
|
||||
<entry><varname>$XDG_CONFIG_HOME</varname></entry>
|
||||
<entry><varname>$STATE_DIRECTORY</varname></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><varname>CacheDirectory=</varname></entry>
|
||||
<entry><filename>/var/cache</filename></entry>
|
||||
<entry><varname>$XDG_CACHE_HOME</varname></entry>
|
||||
<entry><varname>$CACHE_DIRECTORY</varname></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><varname>LogsDirectory=</varname></entry>
|
||||
<entry><filename>/var/log</filename></entry>
|
||||
<entry><varname>$XDG_CONFIG_HOME</varname><filename>/log</filename></entry>
|
||||
<entry><varname>$LOGS_DIRECTORY</varname></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><varname>ConfigurationDirectory=</varname></entry>
|
||||
<entry><filename>/etc</filename></entry>
|
||||
<entry><varname>$XDG_CONFIG_HOME</varname></entry>
|
||||
<entry><varname>$CONFIGURATION_DIRECTORY</varname></entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
|
@ -899,7 +907,13 @@ CapabilityBoundingSet=~CAP_B CAP_C</programlisting>
|
|||
<filename>/run/foo/bar</filename>, and <filename>/run/baz</filename>. The directories
|
||||
<filename>/run/foo/bar</filename> and <filename>/run/baz</filename> except <filename>/run/foo</filename> are
|
||||
owned by the user and group specified in <varname>User=</varname> and <varname>Group=</varname>, and removed
|
||||
when the service is stopped.</para></listitem>
|
||||
when the service is stopped.</para>
|
||||
|
||||
<para>Example: if a system service unit has the following,
|
||||
<programlisting>RuntimeDirectory=foo/bar
|
||||
StateDirectory=aaa/bbb ccc</programlisting>
|
||||
then the environment variable <literal>RUNTIME_DIRECTORY</literal> is set with <literal>/run/foo/bar</literal>, and
|
||||
<literal>STATE_DIRECTORY</literal> is set with <literal>/var/lib/aaa/bbb:/var/lib/ccc</literal>.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
|
|
|
@ -339,21 +339,22 @@ int strv_split_extract(char ***t, const char *s, const char *separators, Extract
|
|||
return (int) n;
|
||||
}
|
||||
|
||||
char *strv_join(char **l, const char *separator) {
|
||||
char *strv_join_prefix(char **l, const char *separator, const char *prefix) {
|
||||
char *r, *e;
|
||||
char **s;
|
||||
size_t n, k;
|
||||
size_t n, k, m;
|
||||
|
||||
if (!separator)
|
||||
separator = " ";
|
||||
|
||||
k = strlen(separator);
|
||||
m = strlen_ptr(prefix);
|
||||
|
||||
n = 0;
|
||||
STRV_FOREACH(s, l) {
|
||||
if (s != l)
|
||||
n += k;
|
||||
n += strlen(*s);
|
||||
n += m + strlen(*s);
|
||||
}
|
||||
|
||||
r = new(char, n+1);
|
||||
|
@ -365,6 +366,9 @@ char *strv_join(char **l, const char *separator) {
|
|||
if (s != l)
|
||||
e = stpcpy(e, separator);
|
||||
|
||||
if (prefix)
|
||||
e = stpcpy(e, prefix);
|
||||
|
||||
e = stpcpy(e, *s);
|
||||
}
|
||||
|
||||
|
|
|
@ -71,7 +71,10 @@ char **strv_split_newlines(const char *s);
|
|||
|
||||
int strv_split_extract(char ***t, const char *s, const char *separators, ExtractFlags flags);
|
||||
|
||||
char *strv_join(char **l, const char *separator);
|
||||
char *strv_join_prefix(char **l, const char *separator, const char *prefix);
|
||||
static inline char *strv_join(char **l, const char *separator) {
|
||||
return strv_join_prefix(l, separator, NULL);
|
||||
}
|
||||
|
||||
char **strv_parse_nulstr(const char *s, size_t l);
|
||||
char **strv_split_nulstr(const char *s);
|
||||
|
|
|
@ -1602,6 +1602,8 @@ static void do_idle_pipe_dance(int idle_pipe[4]) {
|
|||
idle_pipe[3] = safe_close(idle_pipe[3]);
|
||||
}
|
||||
|
||||
static const char *exec_directory_env_name_to_string(ExecDirectoryType t);
|
||||
|
||||
static int build_environment(
|
||||
const Unit *u,
|
||||
const ExecContext *c,
|
||||
|
@ -1615,14 +1617,16 @@ static int build_environment(
|
|||
char ***ret) {
|
||||
|
||||
_cleanup_strv_free_ char **our_env = NULL;
|
||||
ExecDirectoryType t;
|
||||
size_t n_env = 0;
|
||||
char *x;
|
||||
|
||||
assert(u);
|
||||
assert(c);
|
||||
assert(p);
|
||||
assert(ret);
|
||||
|
||||
our_env = new0(char*, 14);
|
||||
our_env = new0(char*, 14 + _EXEC_DIRECTORY_TYPE_MAX);
|
||||
if (!our_env)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -1727,8 +1731,37 @@ static int build_environment(
|
|||
our_env[n_env++] = x;
|
||||
}
|
||||
|
||||
for (t = 0; t < _EXEC_DIRECTORY_TYPE_MAX; t++) {
|
||||
_cleanup_free_ char *pre = NULL, *joined = NULL;
|
||||
const char *n;
|
||||
|
||||
if (!p->prefix[t])
|
||||
continue;
|
||||
|
||||
if (strv_isempty(c->directories[t].paths))
|
||||
continue;
|
||||
|
||||
n = exec_directory_env_name_to_string(t);
|
||||
if (!n)
|
||||
continue;
|
||||
|
||||
pre = strjoin(p->prefix[t], "/");
|
||||
if (!pre)
|
||||
return -ENOMEM;
|
||||
|
||||
joined = strv_join_prefix(c->directories[t].paths, ":", pre);
|
||||
if (!joined)
|
||||
return -ENOMEM;
|
||||
|
||||
x = strjoin(n, "=", joined);
|
||||
if (!x)
|
||||
return -ENOMEM;
|
||||
|
||||
our_env[n_env++] = x;
|
||||
}
|
||||
|
||||
our_env[n_env++] = NULL;
|
||||
assert(n_env <= 12);
|
||||
assert(n_env <= 14 + _EXEC_DIRECTORY_TYPE_MAX);
|
||||
|
||||
*ret = TAKE_PTR(our_env);
|
||||
|
||||
|
@ -5121,6 +5154,16 @@ static const char* const exec_directory_type_table[_EXEC_DIRECTORY_TYPE_MAX] = {
|
|||
|
||||
DEFINE_STRING_TABLE_LOOKUP(exec_directory_type, ExecDirectoryType);
|
||||
|
||||
static const char* const exec_directory_env_name_table[_EXEC_DIRECTORY_TYPE_MAX] = {
|
||||
[EXEC_DIRECTORY_RUNTIME] = "RUNTIME_DIRECTORY",
|
||||
[EXEC_DIRECTORY_STATE] = "STATE_DIRECTORY",
|
||||
[EXEC_DIRECTORY_CACHE] = "CACHE_DIRECTORY",
|
||||
[EXEC_DIRECTORY_LOGS] = "LOGS_DIRECTORY",
|
||||
[EXEC_DIRECTORY_CONFIGURATION] = "CONFIGURATION_DIRECTORY",
|
||||
};
|
||||
|
||||
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(exec_directory_env_name, ExecDirectoryType);
|
||||
|
||||
static const char* const exec_keyring_mode_table[_EXEC_KEYRING_MODE_MAX] = {
|
||||
[EXEC_KEYRING_INHERIT] = "inherit",
|
||||
[EXEC_KEYRING_PRIVATE] = "private",
|
||||
|
|
|
@ -297,7 +297,7 @@ static void test_shift_path(void) {
|
|||
test_shift_path_one("/foobar/waldo", "/", "/foobar/waldo");
|
||||
test_shift_path_one("/foobar/waldo", "", "/foobar/waldo");
|
||||
test_shift_path_one("/foobar/waldo", "/foobar", "/waldo");
|
||||
test_shift_path_one("/foobar/waldo", "/fuckfuck", "/foobar/waldo");
|
||||
test_shift_path_one("/foobar/waldo", "/hogehoge", "/foobar/waldo");
|
||||
}
|
||||
|
||||
static void test_mask_supported(void) {
|
||||
|
|
|
@ -144,6 +144,38 @@ static void test_strv_join(void) {
|
|||
assert_se(streq(w, ""));
|
||||
}
|
||||
|
||||
static void test_strv_join_prefix(void) {
|
||||
_cleanup_free_ char *p = NULL, *q = NULL, *r = NULL, *s = NULL, *t = NULL, *v = NULL, *w = NULL;
|
||||
|
||||
p = strv_join_prefix((char **)input_table_multiple, ", ", "foo");
|
||||
assert_se(p);
|
||||
assert_se(streq(p, "fooone, footwo, foothree"));
|
||||
|
||||
q = strv_join_prefix((char **)input_table_multiple, ";", "foo");
|
||||
assert_se(q);
|
||||
assert_se(streq(q, "fooone;footwo;foothree"));
|
||||
|
||||
r = strv_join_prefix((char **)input_table_multiple, NULL, "foo");
|
||||
assert_se(r);
|
||||
assert_se(streq(r, "fooone footwo foothree"));
|
||||
|
||||
s = strv_join_prefix((char **)input_table_one, ", ", "foo");
|
||||
assert_se(s);
|
||||
assert_se(streq(s, "fooone"));
|
||||
|
||||
t = strv_join_prefix((char **)input_table_none, ", ", "foo");
|
||||
assert_se(t);
|
||||
assert_se(streq(t, ""));
|
||||
|
||||
v = strv_join_prefix((char **)input_table_two_empties, ", ", "foo");
|
||||
assert_se(v);
|
||||
assert_se(streq(v, "foo, foo"));
|
||||
|
||||
w = strv_join_prefix((char **)input_table_one_empty, ", ", "foo");
|
||||
assert_se(w);
|
||||
assert_se(streq(w, "foo"));
|
||||
}
|
||||
|
||||
static void test_strv_unquote(const char *quoted, char **list) {
|
||||
_cleanup_strv_free_ char **s;
|
||||
_cleanup_free_ char *j;
|
||||
|
@ -252,18 +284,18 @@ static void test_strv_split_nulstr(void) {
|
|||
|
||||
static void test_strv_parse_nulstr(void) {
|
||||
_cleanup_strv_free_ char **l = NULL;
|
||||
const char nulstr[] = "fuck\0fuck2\0fuck3\0\0fuck5\0\0xxx";
|
||||
const char nulstr[] = "hoge\0hoge2\0hoge3\0\0hoge5\0\0xxx";
|
||||
|
||||
l = strv_parse_nulstr(nulstr, sizeof(nulstr)-1);
|
||||
assert_se(l);
|
||||
puts("Parse nulstr:");
|
||||
strv_print(l);
|
||||
|
||||
assert_se(streq(l[0], "fuck"));
|
||||
assert_se(streq(l[1], "fuck2"));
|
||||
assert_se(streq(l[2], "fuck3"));
|
||||
assert_se(streq(l[0], "hoge"));
|
||||
assert_se(streq(l[1], "hoge2"));
|
||||
assert_se(streq(l[2], "hoge3"));
|
||||
assert_se(streq(l[3], ""));
|
||||
assert_se(streq(l[4], "fuck5"));
|
||||
assert_se(streq(l[4], "hoge5"));
|
||||
assert_se(streq(l[5], ""));
|
||||
assert_se(streq(l[6], "xxx"));
|
||||
}
|
||||
|
@ -726,6 +758,7 @@ int main(int argc, char *argv[]) {
|
|||
test_strv_find_prefix();
|
||||
test_strv_find_startswith();
|
||||
test_strv_join();
|
||||
test_strv_join_prefix();
|
||||
|
||||
test_strv_unquote(" foo=bar \"waldo\" zzz ", STRV_MAKE("foo=bar", "waldo", "zzz"));
|
||||
test_strv_unquote("", STRV_MAKE_EMPTY);
|
||||
|
|
|
@ -10,6 +10,7 @@ ExecStart=test -d /var/lib/test-dynamicuser-migrate
|
|||
ExecStart=test -d /var/lib/test-dynamicuser-migrate2/hoge
|
||||
ExecStart=touch /var/lib/test-dynamicuser-migrate/yay
|
||||
ExecStart=touch /var/lib/test-dynamicuser-migrate2/hoge/yayyay
|
||||
ExecStart=/bin/sh -x -c 'test "$$STATE_DIRECTORY" = "%S/test-dynamicuser-migrate:%S/test-dynamicuser-migrate2/hoge"'
|
||||
|
||||
Type=oneshot
|
||||
DynamicUser=no
|
||||
|
|
|
@ -18,6 +18,7 @@ ExecStart=touch /var/lib/test-dynamicuser-migrate/yay
|
|||
ExecStart=touch /var/lib/test-dynamicuser-migrate2/hoge/yayyay
|
||||
ExecStart=touch /var/lib/private/test-dynamicuser-migrate/yay
|
||||
ExecStart=touch /var/lib/private/test-dynamicuser-migrate2/hoge/yayyay
|
||||
ExecStart=/bin/sh -x -c 'test "$$STATE_DIRECTORY" = "%S/test-dynamicuser-migrate:%S/test-dynamicuser-migrate2/hoge"'
|
||||
|
||||
Type=oneshot
|
||||
DynamicUser=yes
|
||||
|
|
|
@ -10,6 +10,7 @@ ExecStart=test -f /var/lib/waldo/yay
|
|||
ExecStart=test -f /var/lib/quux/pief/yayyay
|
||||
ExecStart=test -f /var/lib/private/waldo/yay
|
||||
ExecStart=test -f /var/lib/private/quux/pief/yayyay
|
||||
ExecStart=/bin/sh -x -c 'test "$$STATE_DIRECTORY" = "%S/waldo:%S/quux/pief"'
|
||||
|
||||
# Make sure that /var/lib/private/waldo is really the only writable directory besides the obvious candidates
|
||||
ExecStart=sh -x -c 'test $$(find / \( -path /var/tmp -o -path /tmp -o -path /proc -o -path /dev/mqueue -o -path /dev/shm -o -path /sys/fs/bpf \) -prune -o -type d -writable -print 2>/dev/null | sort -u | tr -d '\\\\n') = /var/lib/private/quux/pief/var/lib/private/waldo'
|
||||
|
|
|
@ -3,6 +3,7 @@ Description=Test for RuntimeDirectoryMode
|
|||
|
||||
[Service]
|
||||
ExecStart=/bin/sh -x -c 'mode=$$(stat -c %%a %t/test-exec_runtimedirectory-mode); test "$$mode" = "750"'
|
||||
ExecStart=/bin/sh -x -c 'test "$$RUNTIME_DIRECTORY" = "%t/test-exec_runtimedirectory-mode"'
|
||||
Type=oneshot
|
||||
RuntimeDirectory=test-exec_runtimedirectory-mode
|
||||
RuntimeDirectoryMode=0750
|
||||
|
|
|
@ -4,6 +4,7 @@ Description=Test for RuntimeDirectory
|
|||
[Service]
|
||||
ExecStart=/bin/sh -x -c 'test -d %t/test-exec_runtimedirectory'
|
||||
ExecStart=/bin/sh -x -c 'test -d %t/test-exec_runtimedirectory2/hogehoge'
|
||||
ExecStart=/bin/sh -x -c 'test "$$RUNTIME_DIRECTORY" = "%t/test-exec_runtimedirectory:%t/test-exec_runtimedirectory2/hogehoge"'
|
||||
Type=oneshot
|
||||
RuntimeDirectory=test-exec_runtimedirectory
|
||||
RuntimeDirectory=./test-exec_runtimedirectory2///./hogehoge/.
|
||||
|
|
Loading…
Reference in New Issue