summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--man/tmpfiles.d.xml33
-rw-r--r--src/shared/util.c40
-rw-r--r--src/shared/util.h2
-rw-r--r--src/tmpfiles/tmpfiles.c84
4 files changed, 131 insertions, 28 deletions
diff --git a/man/tmpfiles.d.xml b/man/tmpfiles.d.xml
index 2d8af981e9..6b2753549c 100644
--- a/man/tmpfiles.d.xml
+++ b/man/tmpfiles.d.xml
@@ -169,7 +169,15 @@ L /tmp/foobar - - - - /dev/null</programlisting>
<varlistentry>
<term><varname>p</varname></term>
- <listitem><para>Create a named pipe (FIFO) if it does not exist yet.</para></listitem>
+ <term><varname>p+</varname></term>
+ <listitem><para>Create a named
+ pipe (FIFO) if it does not
+ exist yet. If suffixed with
+ <varname>+</varname> and a
+ file already exists where the
+ pipe is to be created it will
+ be removed and be replaced by
+ the pipe.</para></listitem>
</varlistentry>
<varlistentry>
@@ -188,12 +196,31 @@ L /tmp/foobar - - - - /dev/null</programlisting>
<varlistentry>
<term><varname>c</varname></term>
- <listitem><para>Create a character device node if it does not exist yet.</para></listitem>
+ <term><varname>c+</varname></term>
+ <listitem><para>Create a
+ character device node if it
+ does not exist yet. If
+ suffixed with
+ <varname>+</varname> and a
+ file already exists where the
+ device node is to be created
+ it will be removed and be
+ replaced by the device
+ node.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>b</varname></term>
- <listitem><para>Create a block device node if it does not exist yet.</para></listitem>
+ <term><varname>b+</varname></term>
+ <listitem><para>Create a block
+ device node if it does not
+ exist yet. If suffixed with
+ <varname>+</varname> and a
+ file already exists where the
+ device node is to be created
+ it will be removed and be
+ replaced by the device
+ node.</para></listitem>
</varlistentry>
<varlistentry>
diff --git a/src/shared/util.c b/src/shared/util.c
index fe05820395..bce4e634c2 100644
--- a/src/shared/util.c
+++ b/src/shared/util.c
@@ -4145,6 +4145,46 @@ int symlink_atomic(const char *from, const char *to) {
return 0;
}
+int mknod_atomic(const char *path, mode_t mode, dev_t dev) {
+ _cleanup_free_ char *t = NULL;
+
+ assert(path);
+
+ t = tempfn_random(path);
+ if (!t)
+ return -ENOMEM;
+
+ if (mknod(t, mode, dev) < 0)
+ return -errno;
+
+ if (rename(t, path) < 0) {
+ unlink_noerrno(t);
+ return -errno;
+ }
+
+ return 0;
+}
+
+int mkfifo_atomic(const char *path, mode_t mode) {
+ _cleanup_free_ char *t = NULL;
+
+ assert(path);
+
+ t = tempfn_random(path);
+ if (!t)
+ return -ENOMEM;
+
+ if (mkfifo(t, mode) < 0)
+ return -errno;
+
+ if (rename(t, path) < 0) {
+ unlink_noerrno(t);
+ return -errno;
+ }
+
+ return 0;
+}
+
bool display_is_local(const char *display) {
assert(display);
diff --git a/src/shared/util.h b/src/shared/util.h
index 73f7c0ad4c..6ad43cd274 100644
--- a/src/shared/util.h
+++ b/src/shared/util.h
@@ -523,6 +523,8 @@ int terminal_vhangup(const char *name);
int vt_disallocate(const char *name);
int symlink_atomic(const char *from, const char *to);
+int mknod_atomic(const char *path, mode_t mode, dev_t dev);
+int mkfifo_atomic(const char *path, mode_t mode);
int fchmod_umask(int fd, mode_t mode);
diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c
index 0c1c2b17f4..8ec8252a7b 100644
--- a/src/tmpfiles/tmpfiles.c
+++ b/src/tmpfiles/tmpfiles.c
@@ -721,25 +721,42 @@ static int create_item(Item *i) {
case CREATE_FIFO:
- label_context_set(i->path, S_IFIFO);
RUN_WITH_UMASK(0000) {
+ label_context_set(i->path, S_IFIFO);
r = mkfifo(i->path, i->mode);
+ label_context_clear();
}
- label_context_clear();
- if (r < 0 && errno != EEXIST) {
- log_error("Failed to create fifo %s: %m", i->path);
- return -errno;
- }
+ if (r < 0) {
+ if (errno != EEXIST) {
+ log_error("Failed to create fifo %s: %m", i->path);
+ return -errno;
+ }
- if (stat(i->path, &st) < 0) {
- log_error("stat(%s) failed: %m", i->path);
- return -errno;
- }
+ if (stat(i->path, &st) < 0) {
+ log_error("stat(%s) failed: %m", i->path);
+ return -errno;
+ }
- if (!S_ISFIFO(st.st_mode)) {
- log_error("%s is not a fifo.", i->path);
- return -EEXIST;
+ if (!S_ISFIFO(st.st_mode)) {
+
+ if (i->force) {
+
+ RUN_WITH_UMASK(0000) {
+ label_context_set(i->path, S_IFIFO);
+ r = mkfifo_atomic(i->path, i->mode);
+ label_context_clear();
+ }
+
+ if (r < 0) {
+ log_error("Failed to create fifo %s: %s", i->path, strerror(-r));
+ return r;
+ }
+ } else {
+ log_debug("%s is not a fifo.", i->path);
+ return 0;
+ }
+ }
}
r = item_set_perms(i, i->path);
@@ -771,11 +788,13 @@ static int create_item(Item *i) {
label_context_clear();
if (r < 0) {
- log_error("symlink(%s, %s) failed: %m", i->argument, i->path);
- return -errno;
+ log_error("symlink(%s, %s) failed: %s", i->argument, i->path, strerror(-r));
+ return r;
}
- } else
+ } else {
log_debug("%s is not a symlink or does not point to the correct path.", i->path);
+ return 0;
+ }
}
}
@@ -795,7 +814,7 @@ static int create_item(Item *i) {
return 0;
}
- file_type = (i->type == CREATE_BLOCK_DEVICE ? S_IFBLK : S_IFCHR);
+ file_type = i->type == CREATE_BLOCK_DEVICE ? S_IFBLK : S_IFCHR;
RUN_WITH_UMASK(0000) {
label_context_set(i->path, file_type);
@@ -814,16 +833,31 @@ static int create_item(Item *i) {
log_error("Failed to create device node %s: %m", i->path);
return -errno;
}
- }
- if (stat(i->path, &st) < 0) {
- log_error("stat(%s) failed: %m", i->path);
- return -errno;
- }
+ if (stat(i->path, &st) < 0) {
+ log_error("stat(%s) failed: %m", i->path);
+ return -errno;
+ }
- if ((st.st_mode & S_IFMT) != file_type) {
- log_error("%s is not a device node.", i->path);
- return -EEXIST;
+ if ((st.st_mode & S_IFMT) != file_type) {
+
+ if (i->force) {
+
+ RUN_WITH_UMASK(0000) {
+ label_context_set(i->path, file_type);
+ r = mknod_atomic(i->path, i->mode | file_type, i->major_minor);
+ label_context_clear();
+ }
+
+ if (r < 0) {
+ log_error("Failed to create device node %s: %s", i->path, strerror(-r));
+ return r;
+ }
+ } else {
+ log_debug("%s is not a device node.", i->path);
+ return 0;
+ }
+ }
}
r = item_set_perms(i, i->path);