#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/sysmacros.h>
#include <sys/wait.h>
#include <unistd.h>

#define xmknod(path, mode, maj, min)                                                                                   \
    if (mknod(path, mode, makedev(maj, min)) < 0) exit(255);

// Too early for console logs (/dev/console is created here!), so we have to resort to exiting with a weird exit code in
// case of failure.
static void populate_devfs()
{
    if (mkdir("/dev", 0755) < 0 && errno != EEXIST) exit(255);

    xmknod("/dev/console", 0666, 1, 0);
    xmknod("/dev/null", 0666, 2, 0);
    xmknod("/dev/zero", 0666, 2, 1);
}

int main()
{
    if (getpid() != 1)
    {
        fprintf(stderr, "error: init not running as PID 1.\n");
        return 1;
    }

    populate_devfs();

    // Before this point, we don't even have an stdin, stdout and stderr. Set it up now so that child processes (and us)
    // can print stuff.
    stdin = fopen("/dev/console", "r");
    stdout = fopen("/dev/console", "w");
    stderr = fopen("/dev/console", "w");

    pid_t ret = fork();

    if (ret == 0)
    {
        char* argv[] = { "/bin/sh", NULL };
        char* envp[] = { "PATH=/bin:/sbin", NULL };
        execve(argv[0], argv, envp);
        perror("execv");
        return 1;
    }

    while (1) wait(NULL);
}