From: Tulio A M Mendes Date: Thu, 11 Jun 2026 03:39:26 +0000 (-0300) Subject: rootfs-handoff: Milestone C - integrate pivot_root in early /init X-Git-Url: https://projects.tadryanom.me/?a=commitdiff_plain;h=ef509611e2be33acd353bfd3cfd91696992306f1;p=AdrOS.git rootfs-handoff: Milestone C - integrate pivot_root in early /init - Added full pivot_root implementation to initrd_init.c - Added mkdir_p() for recursive directory creation - Added mount_virtual_fs() to mount virtual filesystems - Added move_mount() to move mounts using MS_MOVE flag - Early /init now moves /dev, /proc, /tmp to /newroot - Performs pivot_root to make /newroot the new root - Unmounts old root after pivot - Executes /sbin/init from the new root - Added MS_MOVE definition (not in ulibc) - Fixed includes to use ulibc headers (syscall.h instead of sys/syscall.h) - Used pivot_root() wrapper from ulibc instead of raw syscall Test Results: - Smoke test: 131/131 PASS - Battery test: 157/157 PASS - Analyzer: PASS - Zero regressions --- diff --git a/user/cmds/initrd_init/Makefile b/user/cmds/initrd_init/Makefile index d741b0a1..11d42b84 100644 --- a/user/cmds/initrd_init/Makefile +++ b/user/cmds/initrd_init/Makefile @@ -6,6 +6,7 @@ # # Source: https://github.com/tadryanom/AdrOS # +# Makefile for initrd_init (early /init for root handoff) NAME := initrd_init SRCS := initrd_init.c diff --git a/user/cmds/initrd_init/initrd_init.c b/user/cmds/initrd_init/initrd_init.c index 7771519b..90437230 100644 --- a/user/cmds/initrd_init/initrd_init.c +++ b/user/cmds/initrd_init/initrd_init.c @@ -12,18 +12,58 @@ * * This program runs from the initrd before the final /sbin/init. * - * Milestone B: Basic early init - checks for /newroot and executes /sbin/init - * Milestone C: Will add pivot_root and mount moving + * Milestone C: Full pivot_root implementation + * - Move virtual filesystems (/dev, /proc, /tmp) to /newroot + * - Perform pivot_root to make /newroot the new root + * - Unmount old root + * - Execute /sbin/init from the new root */ #include #include #include #include +#include #include #include +/* MS_MOVE is not defined in ulibc, define it manually */ +#ifndef MS_MOVE +#define MS_MOVE 8192 +#endif + #define NEWROOT "/newroot" +#define OLDROOT "/oldroot" + +static int mkdir_p(const char* path) { + char tmp[256]; + char* p = NULL; + size_t len; + + snprintf(tmp, sizeof(tmp), "%s", path); + len = strlen(tmp); + if (tmp[len - 1] == '/') { + tmp[len - 1] = 0; + } + + for (p = tmp + 1; *p; p++) { + if (*p == '/') { + *p = 0; + if (mkdir(tmp, 0755) < 0 && errno != EEXIST) { + perror("mkdir_p"); + return -1; + } + *p = '/'; + } + } + + if (mkdir(tmp, 0755) < 0 && errno != EEXIST) { + perror("mkdir_p"); + return -1; + } + + return 0; +} static int is_mounted(const char* path) { FILE* fp = fopen("/proc/mounts", "r"); @@ -47,6 +87,41 @@ static int is_mounted(const char* path) { return found; } +static int mount_virtual_fs(const char* fstype, const char* target) { + if (is_mounted(target)) { + printf("[init] %s already mounted on %s\n", fstype, target); + return 0; + } + + if (mkdir_p(target) < 0) { + return -1; + } + + printf("[init] mounting %s on %s\n", fstype, target); + if (mount("none", target, fstype, 0, NULL) < 0) { + perror("mount"); + return -1; + } + + return 0; +} + +static int move_mount(const char* src, const char* dst) { + printf("[init] moving mount from %s to %s\n", src, dst); + + if (mkdir_p(dst) < 0) { + return -1; + } + + /* Linux uses MS_MOVE flag for mount --move */ + if (mount(src, dst, NULL, MS_MOVE, NULL) < 0) { + perror("mount --move"); + return -1; + } + + return 0; +} + int main(int argc __attribute__((unused)), char** argv) { printf("[init] early userspace init starting\n"); @@ -59,13 +134,73 @@ int main(int argc __attribute__((unused)), char** argv) { return 1; } - printf("[init] /newroot is mounted by kernel\n"); - printf("[init] Milestone B: basic handoff - executing /sbin/init directly\n"); - printf("[init] (pivot_root and mount moving will be added in Milestone C)\n"); + printf("[init] /newroot is mounted, preparing handoff\n"); + + /* Create /oldroot for pivot_root */ + if (mkdir(OLDROOT, 0755) < 0 && errno != EEXIST) { + perror("mkdir /oldroot"); + return 1; + } + + /* Move virtual filesystems to /newroot if they exist on old root */ + const char* virtual_mounts[] = { "/dev", "/proc", "/tmp", NULL }; + for (int i = 0; virtual_mounts[i]; i++) { + char src[128]; + char dst[128]; + + snprintf(src, sizeof(src), "%s", virtual_mounts[i]); + snprintf(dst, sizeof(dst), "%s%s", NEWROOT, virtual_mounts[i]); + + if (is_mounted(src)) { + if (move_mount(src, dst) < 0) { + printf("[init] warning: failed to move %s, will remount\n", src); + /* Fallback: mount directly on new root */ + const char* fstype = NULL; + if (strcmp(src, "/dev") == 0) fstype = "devfs"; + else if (strcmp(src, "/proc") == 0) fstype = "procfs"; + else if (strcmp(src, "/tmp") == 0) fstype = "tmpfs"; + + if (fstype) { + mount_virtual_fs(fstype, dst); + } + } + } else { + /* Not mounted on old root, mount directly on new root */ + const char* fstype = NULL; + if (strcmp(src, "/dev") == 0) fstype = "devfs"; + else if (strcmp(src, "/proc") == 0) fstype = "procfs"; + else if (strcmp(src, "/tmp") == 0) fstype = "tmpfs"; + + if (fstype) { + mount_virtual_fs(fstype, dst); + } + } + } + + /* Perform pivot_root */ + printf("[init] performing pivot_root(%s, %s)\n", NEWROOT, OLDROOT); + if (pivot_root(NEWROOT, OLDROOT) < 0) { + perror("pivot_root"); + printf("[init] pivot_root failed, falling back to /sbin/init\n"); + execve("/sbin/init", argv, environ); + return 1; + } + + /* Change to new root */ + if (chdir("/") < 0) { + perror("chdir /"); + return 1; + } + + /* Unmount old root */ + printf("[init] unmounting %s\n", OLDROOT); + if (umount2(OLDROOT, 0) < 0) { + perror("umount2 /oldroot"); + printf("[init] warning: failed to unmount old root\n"); + } - /* For now, just execute /sbin/init from the initrd overlay */ - /* The kernel has already mounted the real root on /newroot */ - /* Future Milestone C will implement pivot_root to make /newroot the actual root */ + /* Execute final init from new root */ + printf("[init] executing /sbin/init from new root\n"); execve("/sbin/init", argv, environ); perror("execve /sbin/init");