tmpfiles: add "+" modifier support to b, c, p lines in addition to L

This commit is contained in:
Lennart Poettering 2014-06-17 23:50:22 +02:00
parent 0a498f163a
commit 1554afae54
4 changed files with 132 additions and 29 deletions

View File

@ -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>

View File

@ -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);

View File

@ -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);

View File

@ -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();
if (r < 0 && errno != EEXIST) {
log_error("Failed to create fifo %s: %m", i->path);
return -errno;
label_context_clear();
}
if (stat(i->path, &st) < 0) {
log_error("stat(%s) failed: %m", i->path);
return -errno;
}
if (r < 0) {
if (errno != EEXIST) {
log_error("Failed to create fifo %s: %m", i->path);
return -errno;
}
if (!S_ISFIFO(st.st_mode)) {
log_error("%s is not a fifo.", i->path);
return -EEXIST;
if (stat(i->path, &st) < 0) {
log_error("stat(%s) failed: %m", i->path);
return -errno;
}
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);