#include "log.h"
#include "util.h"
#include "macro.h"
+#include "missing.h"
#include "mkdir.h"
#include "path-util.h"
#include "strv.h"
return true;
}
+static int dir_is_mount_point(DIR *d, const char *subdir) {
+ struct file_handle *h;
+ int mount_id_parent, mount_id;
+ int r_p, r;
+
+ h = alloca(MAX_HANDLE_SZ);
+
+ h->handle_bytes = MAX_HANDLE_SZ;
+ r_p = name_to_handle_at(dirfd(d), ".", h, &mount_id_parent, 0);
+ if (r_p < 0)
+ r_p = -errno;
+
+ h->handle_bytes = MAX_HANDLE_SZ;
+ r = name_to_handle_at(dirfd(d), subdir, h, &mount_id, 0);
+ if (r < 0)
+ r = -errno;
+
+ /* got no handle; make no assumptions, return error */
+ if (r_p < 0 && r < 0)
+ return r_p;
+
+ /* got both handles; if they differ, it is a mount point */
+ if (r_p >= 0 && r >= 0)
+ return mount_id_parent != mount_id;
+
+ /* got only one handle; assume different mount points if one
+ * of both queries was not supported by the filesystem */
+ if (r_p == -ENOSYS || r_p == -ENOTSUP || r == -ENOSYS || r == -ENOTSUP)
+ return true;
+
+ /* return error */
+ if (r_p < 0)
+ return r_p;
+ return r;
+}
+
static int dir_cleanup(
Item *i,
const char *p,
if (s.st_dev != rootdev)
continue;
+ /* Try to detect bind mounts of the same filesystem instance; they
+ * do not differ in device major/minors. This type of query is not
+ * supported on all kernels or filesystem types though. */
+ if (S_ISDIR(s.st_mode) && dir_is_mount_point(d, dent->d_name) > 0)
+ continue;
+
/* Do not delete read-only files owned by root */
if (s.st_uid == 0 && !(s.st_mode & S_IWUSR))
continue;
static int write_one_file(Item *i, const char *path) {
int r, e, fd, flags;
struct stat st;
- mode_t u;
flags = i->type == CREATE_FILE ? O_CREAT|O_APPEND :
i->type == TRUNCATE_FILE ? O_CREAT|O_TRUNC : 0;
- u = umask(0);
- label_context_set(path, S_IFREG);
- fd = open(path, flags|O_NDELAY|O_CLOEXEC|O_WRONLY|O_NOCTTY|O_NOFOLLOW, i->mode);
- e = errno;
- label_context_clear();
- umask(u);
- errno = e;
+ RUN_WITH_UMASK(0) {
+ label_context_set(path, S_IFREG);
+ fd = open(path, flags|O_NDELAY|O_CLOEXEC|O_WRONLY|O_NOCTTY|O_NOFOLLOW, i->mode);
+ e = errno;
+ label_context_clear();
+ errno = e;
+ }
if (fd < 0) {
if (i->type == WRITE_FILE && errno == ENOENT)
if ((k = glob(i->path, GLOB_NOSORT|GLOB_BRACE, NULL, &g)) != 0) {
if (k != GLOB_NOMATCH) {
- if (errno != 0)
+ if (errno > 0)
errno = EIO;
log_error("glob(%s) failed: %m", i->path);
static int create_item(Item *i) {
int r, e;
- mode_t u;
struct stat st;
assert(i);
case TRUNCATE_DIRECTORY:
case CREATE_DIRECTORY:
- u = umask(0);
- mkdir_parents_label(i->path, 0755);
- r = mkdir(i->path, i->mode);
- umask(u);
+ RUN_WITH_UMASK(0000) {
+ mkdir_parents_label(i->path, 0755);
+ r = mkdir(i->path, i->mode);
+ }
if (r < 0 && errno != EEXIST) {
log_error("Failed to create directory %s: %m", i->path);
case CREATE_FIFO:
- u = umask(0);
- r = mkfifo(i->path, i->mode);
- umask(u);
+ RUN_WITH_UMASK(0000) {
+ r = mkfifo(i->path, i->mode);
+ }
if (r < 0 && errno != EEXIST) {
log_error("Failed to create fifo %s: %m", i->path);
file_type = (i->type == CREATE_BLOCK_DEVICE ? S_IFBLK : S_IFCHR);
- u = umask(0);
- label_context_set(i->path, file_type);
- r = mknod(i->path, i->mode | file_type, i->major_minor);
- e = errno;
- label_context_clear();
- umask(u);
- errno = e;
+ RUN_WITH_UMASK(0000) {
+ label_context_set(i->path, file_type);
+ r = mknod(i->path, i->mode | file_type, i->major_minor);
+ e = errno;
+ label_context_clear();
+ errno = e;
+ }
if (r < 0 && errno != EEXIST) {
log_error("Failed to create device node %s: %m", i->path);
}
static int parse_line(const char *fname, unsigned line, const char *buffer) {
- Item *i, *existing;
+ Item _cleanup_free_ *i = NULL;
+ Item *existing;
char _cleanup_free_
*mode = NULL, *user = NULL, *group = NULL, *age = NULL;
char type;
&n);
if (r < 2) {
log_error("[%s:%u] Syntax error.", fname, line);
- r = -EIO;
- goto finish;
+ return -EIO;
}
if (n >= 0) {
case CREATE_SYMLINK:
if (!i->argument) {
log_error("[%s:%u] Symlink file requires argument.", fname, line);
- r = -EBADMSG;
- goto finish;
+ return -EBADMSG;
}
break;
case WRITE_FILE:
if (!i->argument) {
log_error("[%s:%u] Write file requires argument.", fname, line);
- r = -EBADMSG;
- goto finish;
+ return -EBADMSG;
}
break;
if (!i->argument) {
log_error("[%s:%u] Device file requires argument.", fname, line);
- r = -EBADMSG;
- goto finish;
+ return -EBADMSG;
}
if (sscanf(i->argument, "%u:%u", &major, &minor) != 2) {
log_error("[%s:%u] Can't parse device file major/minor '%s'.", fname, line, i->argument);
- r = -EBADMSG;
- goto finish;
+ return -EBADMSG;
}
i->major_minor = makedev(major, minor);
default:
log_error("[%s:%u] Unknown file type '%c'.", fname, line, type);
- r = -EBADMSG;
- goto finish;
+ return -EBADMSG;
}
i->type = type;
if (!path_is_absolute(i->path)) {
log_error("[%s:%u] Path '%s' not absolute.", fname, line, i->path);
- r = -EBADMSG;
- goto finish;
+ return -EBADMSG;
}
path_kill_slashes(i->path);
- if (arg_prefix && !path_startswith(i->path, arg_prefix)) {
- r = 0;
- goto finish;
- }
+ if (arg_prefix && !path_startswith(i->path, arg_prefix))
+ return 0;
if (user && !streq(user, "-")) {
const char *u = user;
r = get_user_creds(&u, &i->uid, NULL, NULL, NULL);
if (r < 0) {
log_error("[%s:%u] Unknown user '%s'.", fname, line, user);
- goto finish;
+ return r;
}
i->uid_set = true;
r = get_group_creds(&g, &i->gid);
if (r < 0) {
log_error("[%s:%u] Unknown group '%s'.", fname, line, group);
- goto finish;
+ return r;
}
i->gid_set = true;
if (sscanf(mode, "%o", &m) != 1) {
log_error("[%s:%u] Invalid mode '%s'.", fname, line, mode);
- r = -ENOENT;
- goto finish;
+ return -ENOENT;
}
i->mode = m;
a++;
}
- if (parse_usec(a, &i->age) < 0) {
+ if (parse_sec(a, &i->age) < 0) {
log_error("[%s:%u] Invalid age '%s'.", fname, line, age);
- r = -EBADMSG;
- goto finish;
+ return -EBADMSG;
}
i->age_set = true;
if (!item_equal(existing, i))
log_warning("Two or more conflicting lines for %s configured, ignoring.", i->path);
- r = 0;
- goto finish;
+ return 0;
}
r = hashmap_put(h, i->path, i);
if (r < 0) {
log_error("Failed to insert item %s: %s", i->path, strerror(-r));
- goto finish;
+ return r;
}
- i = NULL;
- r = 0;
-
-finish:
- if (i)
- item_free(i);
+ i = NULL; /* avoid cleanup */
- return r;
+ return 0;
}
static int help(void) {