diff options
-rw-r--r-- | man/tmpfiles.d.xml | 33 | ||||
-rw-r--r-- | src/shared/util.c | 40 | ||||
-rw-r--r-- | src/shared/util.h | 2 | ||||
-rw-r--r-- | src/tmpfiles/tmpfiles.c | 84 |
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); |