chiark / gitweb /
tmpfiles: support writing short strings to files, in order to support /sys manipulati...
authorLennart Poettering <lennart@poettering.net>
Wed, 18 Jan 2012 15:39:04 +0000 (16:39 +0100)
committerLennart Poettering <lennart@poettering.net>
Wed, 18 Jan 2012 15:39:04 +0000 (16:39 +0100)
TODO
man/tmpfiles.d.xml
src/tmpfiles.c
src/util.c

diff --git a/TODO b/TODO
index 0c3cc9dec461510bf1c4d9d166e4204df4878f3f..f3eb8c53dc90e31478a1a8f134464663c45079e2 100644 (file)
--- 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
 
index 080da6681bdfcc8294ae05bd09da122549a1c133..25a7c9ba48351d96b84388c65de4a16a6eca5449 100644 (file)
@@ -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>
index 20960196991efb277a519131f32976b377eba53c..f3c38a84339229c48eb68c61891934c0518283db 100644 (file)
@@ -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;
index 8004bebbd1c0f0af997924e8d95a97e7deaef66a..fbc37c4f0cdc05a452b7cf1a789d4e2b162e6dbd 100644 (file)
@@ -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])