Luna/apps/preinit.cpp
apio 16b0531d42
All checks were successful
continuous-integration/drone/push Build is passing
kernel+apps+base+tools: Use Ext2 for the root partition file system
init is now split into two parts: preinit, which lives in the initrd and prepares the root file system for init,
and the actual /usr/bin/init, which lives in the root partition and starts services and reaps zombies.

The kernel now looks for /bin/preinit instead of /bin/init as the executable for the init process.

All configuration files in initrd/etc have been moved to base/etc. (The plan is to have only moon and preinit in the initrd.)

Since the current Ext2 implementation is read-only (and it's on a CDROM so it would be read-only anyways),
/home/selene is a tmpfs (as well as /tmp), to allow for a writable home directory.

The system is slower now, but that's to expect since the Ext2 code doesn't use caching and the ATA code still uses PIO.
2023-07-10 13:05:06 +02:00

87 lines
2.0 KiB
C++

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <unistd.h>
// FIXME: Make this configurable.
#define LUNA_ROOT_PARTITION "/dev/cd0p2"
static void mount_devfs()
{
if (mkdir("/dev", 0755) < 0 && errno != EEXIST && errno != EROFS) exit(255);
if (mount("/dev", "devfs", "devfs") < 0) exit(255);
}
static void open_std_streams()
{
stdin = fopen("/dev/console", "r");
stdout = fopen("/dev/console", "w");
stderr = fopen("/dev/console", "w");
}
static void fail(const char* message)
{
open_std_streams();
fprintf(stderr, "preinit: fatal error: %s\n", message);
exit(255);
}
static void fail_errno(const char* message)
{
int err = errno;
open_std_streams();
fprintf(stderr, "preinit: fatal error: %s (%s)\n", message, strerror(err));
exit(255);
}
static void mount_rootfs()
{
if (mkdir("/osroot", 0755) < 0 && errno != EEXIST) exit(255);
if (mount("/osroot", "ext2", LUNA_ROOT_PARTITION) < 0) fail_errno("Cannot mount the root partition");
}
int main()
{
if (getpid() != 1)
{
fprintf(stderr, "error: preinit must be run as the init process.\n");
return 1;
}
mount_devfs();
mount_rootfs();
struct stat st;
if (stat("/osroot/mnt", &st) < 0 || !S_ISDIR(st.st_mode)) fail("No suitable temporary mountpoint for pivot_root");
// Now that we have mounted the root file system, remove the /dev mount on the current ramfs root.
umount("/dev");
long rc = syscall(SYS_pivot_root, "/osroot", "/osroot/mnt");
if (rc < 0) exit(255);
chdir("/");
umount("/mnt");
// Now, mount the /dev file system on the new root.
mount_devfs();
/*setenv("PATH", "/bin:/usr/bin", 1);
char* argv[] = { "init", nullptr };
char* envp[] = { nullptr };
execvpe(argv[0], argv, envp);*/
char* argv[] = { "/usr/bin/init", nullptr };
execv(argv[0], argv);
fail_errno("Failed to execute init");
return 255;
}