summaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2016-12-14 00:51:37 +0100
committerLennart Poettering <lennart@poettering.net>2016-12-14 00:51:37 +0100
commit8fceda937f3a177d9e27b403fb5e1b34138b05f5 (patch)
tree6453f86079b33adf50355f3c01c0314dce443be1 /src/core
parent34de407a4fca46cdb5e45aae149604fe10102ecf (diff)
namespace: instead of chasing mount symlinks a priori, do so as-we-go
This is relevant as many of the mounts we try to establish only can be followed when some other prior mount that is a prefix of it is established. Hence: move the symlink chasing into the actual mount functions, so that we do it as late as possibly but as early as necessary. Fixes: #4588
Diffstat (limited to 'src/core')
-rw-r--r--src/core/namespace.c86
1 files changed, 34 insertions, 52 deletions
diff --git a/src/core/namespace.c b/src/core/namespace.c
index 1b4bcd5ba4..746ebc45b0 100644
--- a/src/core/namespace.c
+++ b/src/core/namespace.c
@@ -568,7 +568,33 @@ fail:
return r;
}
+static int mount_entry_chase(MountEntry *m, const char *root_directory) {
+ char *chased;
+ int r;
+
+ assert(m);
+
+ /* Since mount() will always follow symlinks and we need to take the different root directory into account we
+ * chase the symlinks on our own first. */
+
+ r = chase_symlinks(mount_entry_path(m), root_directory, 0, &chased);
+ if (r == -ENOENT && m->ignore) {
+ log_debug_errno(r, "Path %s does not exist, ignoring.", mount_entry_path(m));
+ return 0;
+ }
+ if (r < 0)
+ return log_debug_errno(r, "Failed to follow symlinks on %s: %m", mount_entry_path(m));
+
+ log_debug("Followed symlinks %s → %s.", mount_entry_path(m), chased);
+
+ free(m->path_malloc);
+ m->path_malloc = chased;
+
+ return 1;
+}
+
static int apply_mount(
+ const char *root_directory,
MountEntry *m,
const char *tmp_dir,
const char *var_tmp_dir) {
@@ -578,6 +604,10 @@ static int apply_mount(
assert(m);
+ r = mount_entry_chase(m, root_directory);
+ if (r <= 0)
+ return r;
+
log_debug("Applying namespace mount on %s", mount_entry_path(m));
switch (m->mode) {
@@ -604,7 +634,7 @@ static int apply_mount(
case READONLY:
case READWRITE:
- r = path_is_mount_point(mount_entry_path(m), NULL, 0);
+ r = path_is_mount_point(mount_entry_path(m), root_directory, 0);
if (r < 0)
return log_debug_errno(r, "Failed to determine whether %s is already a mount point: %m", mount_entry_path(m));
if (r > 0) /* Nothing to do here, it is already a mount. We just later toggle the MS_RDONLY bit for the mount point if needed. */
@@ -654,50 +684,9 @@ static int make_read_only(MountEntry *m, char **blacklist) {
* already stays this way. This improves compatibility with container managers, where we won't attempt to undo
* read-only mounts already applied. */
- return r;
-}
-
-/* Chase symlinks and remove failed paths from mounts */
-static int chase_all_symlinks(const char *root_directory, MountEntry *m, unsigned *n) {
- MountEntry *f, *t;
- int r = 0;
-
- assert(m);
- assert(n);
-
- /* Since mount() will always follow symlinks and we need to take the different root directory into account we
- * chase the symlinks on our own first. This call wil do so for all entries and remove all entries where we
- * can't resolve the path, and which have been marked for such removal. */
-
- for (f = m, t = m; f < m + *n; f++) {
- _cleanup_free_ char *chased = NULL;
- int k;
-
- k = chase_symlinks(mount_entry_path(f), root_directory, 0, &chased);
- if (k < 0) {
- /* Get only real errors */
- if (r >= 0 && (k != -ENOENT || !f->ignore))
- r = k;
-
- /* Doesn't exist or failed? Then remove it and continue! */
- log_debug_errno(k, "Failed to chase symlinks for %s: %m", mount_entry_path(f));
- f->path_malloc = mfree(f->path_malloc);
- continue;
- }
-
- if (!path_equal(mount_entry_path(f), chased)) {
- log_debug("Chased %s → %s", mount_entry_path(f), chased);
-
- free(f->path_malloc);
- f->path_malloc = chased;
- chased = NULL;
- }
-
- *t = *f;
- t++;
- }
+ if (r == -ENOENT && m->ignore)
+ r = 0;
- *n = t - m;
return r;
}
@@ -838,13 +827,6 @@ int setup_namespace(
if (r < 0)
goto finish;
- /* Resolve symlinks manually first, as mount() will always follow them relative to the host's
- * root. Moreover we want to suppress duplicates based on the resolved paths. This of course is a bit
- * racy. */
- r = chase_all_symlinks(root_directory, mounts, &n_mounts);
- if (r < 0)
- goto finish;
-
qsort(mounts, n_mounts, sizeof(MountEntry), mount_path_compare);
drop_duplicates(mounts, &n_mounts);
@@ -886,7 +868,7 @@ int setup_namespace(
/* First round, add in all special mounts we need */
for (m = mounts; m < mounts + n_mounts; ++m) {
- r = apply_mount(m, tmp_dir, var_tmp_dir);
+ r = apply_mount(root_directory, m, tmp_dir, var_tmp_dir);
if (r < 0)
goto finish;
}