Viewing: initrd_init.c
📄 initrd_init.c (Read Only) ⬅ To go back
// SPDX-License-Identifier: BSD-3-Clause
/*
 * Copyright (c) 2026, Tulio A M Mendes <[email protected]>
 * All rights reserved.
 * See LICENSE for details.
 *
 * Source: https://github.com/tadryanom/AdrOS
 */

/*
 * Early /init for root filesystem handoff
 *
 * This program runs from the initrd before the final /sbin/init.
 * 
 * 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");
    if (!fp) {
        return 0;
    }

    char line[256];
    int found = 0;
    while (fgets(line, sizeof(line), fp)) {
        char mountpoint[128];
        if (sscanf(line, "%*s %127s", mountpoint) == 1) {
            if (strcmp(mountpoint, path) == 0) {
                found = 1;
                break;
            }
        }
    }

    fclose(fp);
    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");

    /* Check if /newroot is already mounted by kernel */
    if (!is_mounted(NEWROOT)) {
        printf("[init] /newroot not mounted by kernel, nothing to do\n");
        printf("[init] falling back to /sbin/init\n");
        execve("/sbin/init", argv, environ);
        perror("execve /sbin/init");
        return 1;
    }

    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");
    }

    /* Execute final init from new root */
    printf("[init] executing /sbin/init from new root\n");
    execve("/sbin/init", argv, environ);
    perror("execve /sbin/init");

    return 1;
}