]> Projects (at) Tadryanom (dot) Me - AdrOS.git/commitdiff
rootfs-handoff: Milestone C - integrate pivot_root in early /init
authorTulio A M Mendes <[email protected]>
Thu, 11 Jun 2026 03:39:26 +0000 (00:39 -0300)
committerTulio A M Mendes <[email protected]>
Thu, 11 Jun 2026 03:39:26 +0000 (00:39 -0300)
- 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

user/cmds/initrd_init/Makefile
user/cmds/initrd_init/initrd_init.c

index d741b0a1006eeb6cb8d652d94a0aca59eebbdc5c..11d42b84fb01eb7eaf2b59acd89293b2c8b43593 100644 (file)
@@ -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
index 7771519b102b6baf3cac5acaf8caa9998c5fe09e..90437230c7e0b55227bed8e3813a187c19ce55f6 100644 (file)
  *
  * 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 <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <sys/mount.h>
 #include <sys/stat.h>
 #include <errno.h>
 
+/* 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");