summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDave Reisner <dreisner@archlinux.org>2012-09-15 12:58:49 -0400
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>2012-09-16 17:18:04 +0200
commit54693d9bfa855841e8097d7a6b8c8d7acc068004 (patch)
tree16ca646639c499bd81f1bffe8d0baa8fa2e83394 /src
parentc65a0b146652cac52fe3c43f7cb8fe6a2ac3e063 (diff)
tmpfiles: use write(2) for the 'w' action
This resolves problems with filesystems which do not implement the aio_write file operation. In this case, the kernel will fall back using a loop writing technique for each pointer in a received iovec. The result is strange errors in dmesg such as: [ 31.855871] elevator: type not found [ 31.856262] elevator: switch to [ 31.856262] failed It does not make sense to implement a synchronous aio_write method for sysfs as this isn't a real filesystem where a reasonable use case for using writev exists, nor is there an expectation that tmpfiles will be used to write more data than can be reasonably written in a single write syscall. In addition, some sysfs attrs are currently buggy and will NOT reject the second write with the newline, causing the sysfs value to be zeroed out. This of course should be fixed in the kernel regardless of any wrongdoing in userspace, but this simple change makes us immune to such a bug. This change means that we do not write a trailing newline by default, as the expected use case of 'w' is for sysfs and procfs. In exchange, honor C-style backslash escapes so that if the newline is really needed, the user can add it.
Diffstat (limited to 'src')
-rw-r--r--src/tmpfiles/tmpfiles.c22
1 files changed, 7 insertions, 15 deletions
diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c
index ed51ec8a7f..5d0f571bea 100644
--- a/src/tmpfiles/tmpfiles.c
+++ b/src/tmpfiles/tmpfiles.c
@@ -42,6 +42,7 @@
#include "log.h"
#include "util.h"
+#include "macro.h"
#include "mkdir.h"
#include "path-util.h"
#include "strv.h"
@@ -503,24 +504,15 @@ static int write_one_file(Item *i, const char *path) {
if (i->argument) {
ssize_t n;
size_t l;
- struct iovec iovec[2];
- static const char new_line = '\n';
+ _cleanup_free_ char *unescaped;
- l = strlen(i->argument);
+ unescaped = cunescape(i->argument);
+ if (unescaped == NULL)
+ return log_oom();
- zero(iovec);
- iovec[0].iov_base = i->argument;
- iovec[0].iov_len = l;
+ l = strlen(unescaped);
+ n = write(fd, unescaped, l);
- iovec[1].iov_base = (void*) &new_line;
- iovec[1].iov_len = 1;
-
- n = writev(fd, iovec, 2);
-
- /* It's OK if we don't write the trailing
- * newline, hence we check for l, instead of
- * l+1 here. Files in /sys often refuse
- * writing of the trailing newline. */
if (n < 0 || (size_t) n < l) {
log_error("Failed to write file %s: %s", path, n < 0 ? strerror(-n) : "Short write");
close_nointr_nofail(fd);