diff options
-rw-r--r-- | TODO | 3 | ||||
-rw-r--r-- | man/tmpfiles.d.xml | 14 | ||||
-rw-r--r-- | src/tmpfiles.c | 70 | ||||
-rw-r--r-- | src/util.c | 3 |
4 files changed, 77 insertions, 13 deletions
@@ -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]) |