From 31ed59c51126fce7d958c188772a397e2a1ed010 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 18 Jan 2012 16:39:04 +0100 Subject: [PATCH] tmpfiles: support writing short strings to files, in order to support /sys manipulations at boot time, a la sysctl --- TODO | 3 +- man/tmpfiles.d.xml | 14 ++++++++-- src/tmpfiles.c | 70 ++++++++++++++++++++++++++++++++++++++++------ src/util.c | 3 +- 4 files changed, 77 insertions(+), 13 deletions(-) diff --git a/TODO b/TODO index 0c3cc9dec..f3eb8c53d 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 080da6681..25a7c9ba4 100644 --- a/man/tmpfiles.d.xml +++ b/man/tmpfiles.d.xml @@ -98,12 +98,17 @@ L /tmp/foobar - - - - /dev/null f - Create a file if it doesn't exist yet + Create a file if it doesn't exist yet (optionally writing a short string into it, if the argument parameter is passed) F - Create or truncate a file + Create or truncate a file (optionally writing a short string into it, if the argument parameter is passed) + + + + w + Write the argument parameter to a file, if it exists. @@ -260,7 +265,10 @@ L /tmp/foobar - - - - /dev/null 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. + 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. diff --git a/src/tmpfiles.c b/src/tmpfiles.c index 209601969..f3c38a843 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 8004bebbd..fbc37c4f0 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]) -- 2.30.2