summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2012-01-18 16:39:04 +0100
committerLennart Poettering <lennart@poettering.net>2012-01-18 16:39:04 +0100
commit31ed59c51126fce7d958c188772a397e2a1ed010 (patch)
tree4283457ed50bb46e3cbf86bcc5bb06e1f3479a1a
parent88f06645623467f9c8db88afca64557d62e38c61 (diff)
tmpfiles: support writing short strings to files, in order to support /sys manipulations at boot time, a la sysctl
-rw-r--r--TODO3
-rw-r--r--man/tmpfiles.d.xml14
-rw-r--r--src/tmpfiles.c70
-rw-r--r--src/util.c3
4 files changed, 77 insertions, 13 deletions
diff --git a/TODO b/TODO
index 0c3cc9dec4..f3eb8c53dc 100644
--- a/TODO
+++ b/TODO
@@ -21,6 +21,8 @@ Bugfixes:
Features:
+* rework namespace support, don't use pivot_root, and mount things after creating the namespace, not before
+
* systemctl journal command
* journalctl: --cursor support, priority filtering
@@ -82,7 +84,6 @@ Features:
* service restart retry configuration
* tmpfiles: apply "x" on "D" too (see patch from William Douglas)
-* tmpfiles: support generation of char/block devices, symlinks and one-line files (think sysfs)
* don't set $HOME in services unless requested
diff --git a/man/tmpfiles.d.xml b/man/tmpfiles.d.xml
index 080da6681b..25a7c9ba48 100644
--- a/man/tmpfiles.d.xml
+++ b/man/tmpfiles.d.xml
@@ -98,12 +98,17 @@ L /tmp/foobar - - - - /dev/null</programlisting>
<variablelist>
<varlistentry>
<term><varname>f</varname></term>
- <listitem><para>Create a file if it doesn't exist yet</para></listitem>
+ <listitem><para>Create a file if it doesn't exist yet (optionally writing a short string into it, if the argument parameter is passed)</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>F</varname></term>
- <listitem><para>Create or truncate a file</para></listitem>
+ <listitem><para>Create or truncate a file (optionally writing a short string into it, if the argument parameter is passed)</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><varname>w</varname></term>
+ <listitem><para>Write the argument parameter to a file, if it exists.</para></listitem>
</varlistentry>
<varlistentry>
@@ -260,7 +265,10 @@ L /tmp/foobar - - - - /dev/null</programlisting>
path of the symlink. For c, b determines the
major/minor of the device node, with major and
minor formatted as integers, separated by :,
- e.g. "1:3". Ignored for all other lines.</para>
+ e.g. "1:3". For f, F, w may be used to specify
+ a short string that is written to the file,
+ suffixed by a newline. Ignored for all other
+ lines.</para>
</refsect2>
</refsect1>
diff --git a/src/tmpfiles.c b/src/tmpfiles.c
index 2096019699..f3c38a8433 100644
--- a/src/tmpfiles.c
+++ b/src/tmpfiles.c
@@ -54,6 +54,7 @@ typedef enum ItemType {
/* These ones take file names */
CREATE_FILE = 'f',
TRUNCATE_FILE = 'F',
+ WRITE_FILE = 'w',
CREATE_DIRECTORY = 'd',
TRUNCATE_DIRECTORY = 'D',
CREATE_FIFO = 'p',
@@ -574,19 +575,48 @@ static int create_item(Item *i) {
return 0;
case CREATE_FILE:
- case TRUNCATE_FILE: {
- int fd;
+ case TRUNCATE_FILE:
+ case WRITE_FILE: {
+ int fd, flags;
+
+ flags = i->type == CREATE_FILE ? O_CREAT|O_APPEND :
+ i->type == TRUNCATE_FILE ? O_CREAT|O_TRUNC : 0;
u = umask(0);
- fd = open(i->path, O_CREAT|O_NDELAY|O_CLOEXEC|O_WRONLY|O_NOCTTY|O_NOFOLLOW|
- (i->type == TRUNCATE_FILE ? O_TRUNC : 0), i->mode);
+ fd = open(i->path, flags|O_NDELAY|O_CLOEXEC|O_WRONLY|O_NOCTTY|O_NOFOLLOW, i->mode);
umask(u);
if (fd < 0) {
+ if (i->type == WRITE_FILE && errno == ENOENT)
+ break;
+
log_error("Failed to create file %s: %m", i->path);
return -errno;
}
+ if (i->argument) {
+ ssize_t n;
+ size_t l;
+ struct iovec iovec[2];
+ static const char new_line = '\n';
+
+ l = strlen(i->argument);
+
+ zero(iovec);
+ iovec[0].iov_base = i->argument;
+ iovec[0].iov_len = l;
+
+ iovec[1].iov_base = (void*) &new_line;
+ iovec[1].iov_len = 1;
+
+ n = writev(fd, iovec, 2);
+ if (n < 0 || (size_t) n != l+1) {
+ log_error("Failed to write file %s: %s", i->path, n < 0 ? strerror(-n) : "Short");
+ close_nointr_nofail(fd);
+ return n < 0 ? n : -EIO;
+ }
+ }
+
close_nointr_nofail(fd);
if (stat(i->path, &st) < 0) {
@@ -752,6 +782,7 @@ static int remove_item_instance(Item *i, const char *instance) {
case IGNORE_PATH:
case RELABEL_PATH:
case RECURSIVE_RELABEL_PATH:
+ case WRITE_FILE:
break;
case REMOVE_PATH:
@@ -793,6 +824,7 @@ static int remove_item(Item *i) {
case IGNORE_PATH:
case RELABEL_PATH:
case RECURSIVE_RELABEL_PATH:
+ case WRITE_FILE:
break;
case REMOVE_PATH:
@@ -857,7 +889,10 @@ static bool item_equal(Item *a, Item *b) {
(a->age_set && a->age != b->age))
return false;
- if (a->type == CREATE_SYMLINK &&
+ if ((a->type == CREATE_FILE ||
+ a->type == TRUNCATE_FILE ||
+ a->type == WRITE_FILE ||
+ a->type == CREATE_SYMLINK) &&
!streq(a->argument, b->argument))
return false;
@@ -874,7 +909,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
char *mode = NULL, *user = NULL, *group = NULL, *age = NULL;
char type;
Hashmap *h;
- int r;
+ int r, n = -1;
assert(fname);
assert(line >= 1);
@@ -893,19 +928,30 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
"%ms "
"%ms "
"%ms "
- "%ms",
+ "%n",
&type,
&i->path,
&mode,
&user,
&group,
&age,
- &i->argument) < 2) {
+ &n) < 2) {
log_error("[%s:%u] Syntax error.", fname, line);
r = -EIO;
goto finish;
}
+ if (n >= 0) {
+ n += strspn(buffer+n, WHITESPACE);
+ if (buffer[n] != 0 && (buffer[n] != '-' || buffer[n+1] != 0)) {
+ i->argument = unquote(buffer+n, "\"");
+ if (!i->argument) {
+ log_error("Out of memory");
+ return -ENOMEM;
+ }
+ }
+ }
+
switch(type) {
case CREATE_FILE:
@@ -928,6 +974,14 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
}
break;
+ case WRITE_FILE:
+ if (!i->argument) {
+ log_error("[%s:%u] Write file requires argument.", fname, line);
+ r = -EBADMSG;
+ goto finish;
+ }
+ break;
+
case CREATE_CHAR_DEVICE:
case CREATE_BLOCK_DEVICE: {
unsigned major, minor;
diff --git a/src/util.c b/src/util.c
index 8004bebbd1..fbc37c4f0c 100644
--- a/src/util.c
+++ b/src/util.c
@@ -4118,7 +4118,8 @@ char *unquote(const char *s, const char* quotes) {
size_t l;
assert(s);
- if ((l = strlen(s)) < 2)
+ l = strlen(s);
+ if (l < 2)
return strdup(s);
if (strchr(quotes, s[0]) && s[l-1] == s[0])