tmpfiles: support simple specifier expansion for specified paths

This commit is contained in:
Lennart Poettering 2013-09-17 11:02:02 -05:00
parent f485606bf8
commit 1731e34a4e
4 changed files with 97 additions and 28 deletions

View file

@ -1542,12 +1542,15 @@ EXTRA_DIST += \
# ------------------------------------------------------------------------------
if ENABLE_TMPFILES
systemd_tmpfiles_SOURCES = \
src/tmpfiles/tmpfiles.c
src/tmpfiles/tmpfiles.c \
src/shared/specifier.c \
src/shared/specifier.h
systemd_tmpfiles_LDADD = \
libsystemd-label.la \
libsystemd-shared.la \
libsystemd-capability.la
libsystemd-capability.la \
libsystemd-id128-internal.la
rootbin_PROGRAMS += \
systemd-tmpfiles

View file

@ -67,7 +67,7 @@
<title>Configuration Format</title>
<para>Each configuration file shall be named in the
style of <filename>&lt;program&gt;.conf</filename>.
style of <filename>&lt;package&gt;.conf</filename>.
Files in <filename>/etc/</filename> override files
with the same name in <filename>/usr/lib/</filename>
and <filename>/run/</filename>. Files in
@ -100,8 +100,12 @@
d /run/user 0755 root root 10d -
L /tmp/foobar - - - - /dev/null</programlisting>
<refsect2>
<title>Type</title>
<para>The following line types are understood:</para>
<variablelist>
<varlistentry>
<term><varname>f</varname></term>
@ -233,6 +237,57 @@ L /tmp/foobar - - - - /dev/null</programlisting>
</variablelist>
</refsect2>
<refsect2>
<title>Path</title>
<para>The file system path specification supports simple specifier
expansion. The following expansions are
understood:</para>
<table>
<title>Specifiers available</title>
<tgroup cols='3' align='left' colsep='1' rowsep='1'>
<colspec colname="spec" />
<colspec colname="mean" />
<colspec colname="detail" />
<thead>
<row>
<entry>Specifier</entry>
<entry>Meaning</entry>
<entry>Details</entry>
</row>
</thead>
<tbody>
<row>
<entry><literal>%m</literal></entry>
<entry>Machine ID</entry>
<entry>The machine ID of the running system, formatted as string. See <citerefentry><refentrytitle>machine-id</refentrytitle><manvolnum>5</manvolnum></citerefentry> for more information.</entry>
</row>
<row>
<entry><literal>%b</literal></entry>
<entry>Boot ID</entry>
<entry>The boot ID of the running system, formatted as string. See <citerefentry><refentrytitle>random</refentrytitle><manvolnum>4</manvolnum></citerefentry> for more information.</entry>
</row>
<row>
<entry><literal>%H</literal></entry>
<entry>Host name</entry>
<entry>The hostname of the running system.</entry>
</row>
<row>
<entry><literal>%v</literal></entry>
<entry>Kernel release</entry>
<entry>Identical to <command>uname -r</command> output.</entry>
</row>
<row>
<entry><literal>%%</literal></entry>
<entry>Escaped %</entry>
<entry>Single percent sign.</entry>
</row>
</tbody>
</tgroup>
</table>
</refsect2>
<refsect2>
<title>Mode</title>

View file

@ -27,19 +27,19 @@
#include "strv.h"
static void test_specifier_printf(void) {
_cleanup_free_ char *w = NULL;
int r;
const Specifier table[] = {
static const Specifier table[] = {
{ 'a', specifier_string, (char*) "AAAA" },
{ 'b', specifier_string, (char*) "BBBB" },
{ 'm', specifier_machine_id, NULL },
{ 'B', specifier_boot_id, NULL },
{ 'H', specifier_host_name, NULL },
{ 'v', specifier_kernel_release, NULL },
{ 0, NULL, NULL }
{}
};
_cleanup_free_ char *w = NULL;
int r;
r = specifier_printf("xxx a=%a b=%b yyy", table, NULL, &w);
assert_se(r >= 0);
assert_se(w);

View file

@ -51,6 +51,7 @@
#include "set.h"
#include "conf-files.h"
#include "capability.h"
#include "specifier.h"
/* This reads all files listed in /etc/tmpfiles.d/?*.conf and creates
* them in the file system. This is intended to be used to create
@ -1038,10 +1039,19 @@ static bool should_include_path(const char *path) {
}
static int parse_line(const char *fname, unsigned line, const char *buffer) {
static const Specifier specifier_table[] = {
{ 'm', specifier_machine_id, NULL },
{ 'b', specifier_boot_id, NULL },
{ 'H', specifier_host_name, NULL },
{ 'v', specifier_kernel_release, NULL },
{}
};
_cleanup_item_free_ Item *i = NULL;
Item *existing;
_cleanup_free_ char
*mode = NULL, *user = NULL, *group = NULL, *age = NULL;
*mode = NULL, *user = NULL, *group = NULL, *age = NULL, *path = NULL;
char type;
Hashmap *h;
int r, n = -1;
@ -1050,14 +1060,10 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
assert(line >= 1);
assert(buffer);
i = new0(Item, 1);
if (!i)
return log_oom();
r = sscanf(buffer,
"%c %ms %ms %ms %ms %ms %n",
&type,
&i->path,
&path,
&mode,
&user,
&group,
@ -1068,6 +1074,16 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
return -EIO;
}
i = new0(Item, 1);
if (!i)
return log_oom();
r = specifier_printf(path, specifier_table, NULL, &i->path);
if (r < 0) {
log_error("[%s:%u] Failed to replace specifiers: %s", fname, line, path);
return r;
}
if (n >= 0) {
n += strspn(buffer+n, WHITESPACE);
if (buffer[n] != 0 && (buffer[n] != '-' || buffer[n+1] != 0)) {
@ -1307,11 +1323,12 @@ static int parse_argv(int argc, char *argv[]) {
}
static int read_config_file(const char *fn, bool ignore_enoent) {
FILE *f;
unsigned v = 0;
int r;
_cleanup_fclose_ FILE *f = NULL;
char line[LINE_MAX];
Iterator iterator;
unsigned v = 0;
Item *i;
int r;
assert(fn);
@ -1324,23 +1341,19 @@ static int read_config_file(const char *fn, bool ignore_enoent) {
return r;
}
log_debug("apply: %s\n", fn);
for (;;) {
char line[LINE_MAX], *l;
FOREACH_LINE(line, f, break) {
char *l;
int k;
if (!(fgets(line, sizeof(line), f)))
break;
v++;
l = strstrip(line);
if (*l == '#' || *l == 0)
continue;
if ((k = parse_line(fn, v, l)) < 0)
if (r == 0)
r = k;
k = parse_line(fn, v, l);
if (k < 0 && r == 0)
r = k;
}
/* we have to determine age parameter for each entry of type X */
@ -1377,8 +1390,6 @@ static int read_config_file(const char *fn, bool ignore_enoent) {
r = -EIO;
}
fclose(f);
return r;
}