mirror of
https://github.com/systemd/systemd.git
synced 2025-01-12 13:18:14 +03:00
mount-util: make sure mount_switch_root() works as clean NOP when '/' is specified as target
This commit is contained in:
parent
1fdab6c306
commit
bb59b92256
@ -457,10 +457,6 @@ static int mount_switch_root_pivot(int fd_newroot, const char *path) {
|
||||
assert(fd_newroot >= 0);
|
||||
assert(path);
|
||||
|
||||
/* Change into the new rootfs. */
|
||||
if (fchdir(fd_newroot) < 0)
|
||||
return log_debug_errno(errno, "Failed to chdir into new rootfs '%s': %m", path);
|
||||
|
||||
/* Let the kernel tuck the new root under the old one. */
|
||||
if (pivot_root(".", ".") < 0)
|
||||
return log_debug_errno(errno, "Failed to pivot root to new rootfs '%s': %m", path);
|
||||
@ -477,10 +473,6 @@ static int mount_switch_root_move(int fd_newroot, const char *path) {
|
||||
assert(fd_newroot >= 0);
|
||||
assert(path);
|
||||
|
||||
/* Change into the new rootfs. */
|
||||
if (fchdir(fd_newroot) < 0)
|
||||
return log_debug_errno(errno, "Failed to chdir into new rootfs '%s': %m", path);
|
||||
|
||||
/* Move the new root fs */
|
||||
if (mount(".", "/", NULL, MS_MOVE, NULL) < 0)
|
||||
return log_debug_errno(errno, "Failed to move new rootfs '%s': %m", path);
|
||||
@ -494,7 +486,7 @@ static int mount_switch_root_move(int fd_newroot, const char *path) {
|
||||
|
||||
int mount_switch_root_full(const char *path, unsigned long mount_propagation_flag, bool force_ms_move) {
|
||||
_cleanup_close_ int fd_newroot = -EBADF;
|
||||
int r;
|
||||
int r, is_current_root;
|
||||
|
||||
assert(path);
|
||||
assert(mount_propagation_flag_is_valid(mount_propagation_flag));
|
||||
@ -503,19 +495,31 @@ int mount_switch_root_full(const char *path, unsigned long mount_propagation_fla
|
||||
if (fd_newroot < 0)
|
||||
return log_debug_errno(errno, "Failed to open new rootfs '%s': %m", path);
|
||||
|
||||
if (!force_ms_move) {
|
||||
r = mount_switch_root_pivot(fd_newroot, path);
|
||||
if (r < 0) {
|
||||
log_debug_errno(r, "Failed to pivot into new rootfs '%s', will try to use MS_MOVE instead: %m", path);
|
||||
force_ms_move = true;
|
||||
is_current_root = path_is_root_at(fd_newroot, NULL);
|
||||
if (is_current_root < 0)
|
||||
return log_debug_errno(is_current_root, "Failed to determine if target dir is our root already: %m");
|
||||
|
||||
/* Change into the new rootfs. */
|
||||
if (fchdir(fd_newroot) < 0)
|
||||
return log_debug_errno(errno, "Failed to chdir into new rootfs '%s': %m", path);
|
||||
|
||||
/* Make this a NOP if we are supposed to switch to our current root fs. After all, both pivot_root()
|
||||
* and MS_MOVE don't like that. */
|
||||
if (!is_current_root) {
|
||||
if (!force_ms_move) {
|
||||
r = mount_switch_root_pivot(fd_newroot, path);
|
||||
if (r < 0) {
|
||||
log_debug_errno(r, "Failed to pivot into new rootfs '%s', will try to use MS_MOVE instead: %m", path);
|
||||
force_ms_move = true;
|
||||
}
|
||||
}
|
||||
if (force_ms_move) {
|
||||
/* Failed to pivot_root() fallback to MS_MOVE. For example, this may happen if the rootfs is
|
||||
* an initramfs in which case pivot_root() isn't supported. */
|
||||
r = mount_switch_root_move(fd_newroot, path);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to switch to new rootfs '%s' with MS_MOVE: %m", path);
|
||||
}
|
||||
}
|
||||
if (force_ms_move) {
|
||||
/* Failed to pivot_root() fallback to MS_MOVE. For example, this may happen if the rootfs is
|
||||
* an initramfs in which case pivot_root() isn't supported. */
|
||||
r = mount_switch_root_move(fd_newroot, path);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to switch to new rootfs '%s' with MS_MOVE: %m", path);
|
||||
}
|
||||
|
||||
/* Finally, let's establish the requested propagation flags. */
|
||||
|
@ -276,7 +276,17 @@ TEST(make_mount_switch_root) {
|
||||
assert_se(s);
|
||||
assert_se(touch(s) >= 0);
|
||||
|
||||
for (int force_ms_move = 0; force_ms_move < 2; force_ms_move++) {
|
||||
struct {
|
||||
const char *path;
|
||||
bool force_ms_move;
|
||||
} table[] = {
|
||||
{ t, false },
|
||||
{ t, true },
|
||||
{ "/", false },
|
||||
{ "/", true },
|
||||
};
|
||||
|
||||
FOREACH_ARRAY(i, table, ELEMENTSOF(table)) {
|
||||
r = safe_fork("(switch-root)",
|
||||
FORK_RESET_SIGNALS |
|
||||
FORK_CLOSE_ALL_FDS |
|
||||
@ -290,12 +300,14 @@ TEST(make_mount_switch_root) {
|
||||
assert_se(r >= 0);
|
||||
|
||||
if (r == 0) {
|
||||
assert_se(make_mount_point(t) >= 0);
|
||||
assert_se(mount_switch_root_full(t, /* mount_propagation_flag= */ 0, force_ms_move) >= 0);
|
||||
assert_se(make_mount_point(i->path) >= 0);
|
||||
assert_se(mount_switch_root_full(i->path, /* mount_propagation_flag= */ 0, i->force_ms_move) >= 0);
|
||||
|
||||
assert_se(access(ASSERT_PTR(strrchr(s, '/')), F_OK) >= 0); /* absolute */
|
||||
assert_se(access(ASSERT_PTR(strrchr(s, '/')) + 1, F_OK) >= 0); /* relative */
|
||||
assert_se(access(s, F_OK) < 0 && errno == ENOENT); /* doesn't exist in our new environment */
|
||||
if (!path_equal(i->path, "/")) {
|
||||
assert_se(access(ASSERT_PTR(strrchr(s, '/')), F_OK) >= 0); /* absolute */
|
||||
assert_se(access(ASSERT_PTR(strrchr(s, '/')) + 1, F_OK) >= 0); /* relative */
|
||||
assert_se(access(s, F_OK) < 0 && errno == ENOENT); /* doesn't exist in our new environment */
|
||||
}
|
||||
|
||||
_exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user