Files
SparkOS/src/init.c
copilot-swe-agent[bot] 927163d8eb Add overlay filesystem support for spark user home directory
- Create separate overlay directories for /var and /home/spark
- Mount overlay on /home/spark for writable user data
- Update welcome message to show /home/spark is writable
- Ensures user files persist across sessions in tmpfs overlay

Co-authored-by: johndoe6345789 <224850594+johndoe6345789@users.noreply.github.com>
2025-12-29 19:58:25 +00:00

158 lines
4.9 KiB
C

/*
* SparkOS Init - Minimal init system for SparkOS
* This is the first process that runs after the kernel boots
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/reboot.h>
#include <signal.h>
#include <errno.h>
#include <string.h>
// Default user configuration
#define SPARK_UID 1000
#define SPARK_GID 1000
#define SPARK_HOME "/home/spark"
#define SPARK_USER "spark"
static void signal_handler(int sig) {
if (sig == SIGCHLD) {
// Reap zombie processes
while (waitpid(-1, NULL, WNOHANG) > 0);
}
}
static void spawn_shell() {
pid_t pid = fork();
if (pid < 0) {
perror("fork failed");
return;
}
if (pid == 0) {
// Child process - exec shell as spark user
// Set user and group IDs to spark user
if (setgid(SPARK_GID) != 0) {
perror("setgid failed");
exit(1);
}
if (setuid(SPARK_UID) != 0) {
perror("setuid failed");
exit(1);
}
char *argv[] = {"/bin/sh", "-l", NULL};
char *envp[] = {
"HOME=" SPARK_HOME,
"PATH=/bin:/sbin:/usr/bin:/usr/sbin",
"TERM=linux",
"PS1=SparkOS$ ",
"USER=" SPARK_USER,
"LOGNAME=" SPARK_USER,
NULL
};
// Change to home directory
if (chdir(SPARK_HOME) != 0) {
perror("chdir failed");
}
execve("/bin/sh", argv, envp);
perror("failed to exec shell");
exit(1);
}
// Parent process - wait for shell to exit
int status;
waitpid(pid, &status, 0);
}
int main(int argc, char *argv[]) {
printf("SparkOS Init System Starting...\n");
// Make sure we're PID 1
if (getpid() != 1) {
fprintf(stderr, "init must be run as PID 1\n");
return 1;
}
// Set up signal handlers
signal(SIGCHLD, signal_handler);
// Mount essential filesystems
printf("Mounting essential filesystems...\n");
if (system("mount -t proc proc /proc 2>/dev/null") != 0) {
fprintf(stderr, "Warning: Failed to mount /proc\n");
}
if (system("mount -t sysfs sys /sys 2>/dev/null") != 0) {
fprintf(stderr, "Warning: Failed to mount /sys\n");
}
if (system("mount -t devtmpfs dev /dev 2>/dev/null") != 0) {
fprintf(stderr, "Warning: Failed to mount /dev\n");
}
if (system("mount -t tmpfs tmpfs /tmp 2>/dev/null") != 0) {
fprintf(stderr, "Warning: Failed to mount /tmp\n");
}
// Set up overlay filesystem for immutable base OS
printf("Setting up overlay filesystem for writable layer...\n");
// Create overlay directories in tmpfs
if (system("mkdir -p /tmp/overlay/var-upper /tmp/overlay/var-work 2>/dev/null") != 0) {
fprintf(stderr, "Warning: Failed to create overlay directories for /var\n");
}
if (system("mkdir -p /tmp/overlay/home-upper /tmp/overlay/home-work 2>/dev/null") != 0) {
fprintf(stderr, "Warning: Failed to create overlay directories for /home/spark\n");
}
// Mount overlay on /var for logs and runtime data
if (system("mount -t overlay overlay -o lowerdir=/var,upperdir=/tmp/overlay/var-upper,workdir=/tmp/overlay/var-work /var 2>/dev/null") != 0) {
fprintf(stderr, "Warning: Failed to mount overlay on /var - system may be read-only\n");
} else {
printf("Overlay filesystem mounted on /var (base OS is immutable)\n");
}
// Mount overlay on /home/spark for user data
if (system("mount -t overlay overlay -o lowerdir=/home/spark,upperdir=/tmp/overlay/home-upper,workdir=/tmp/overlay/home-work /home/spark 2>/dev/null") != 0) {
fprintf(stderr, "Warning: Failed to mount overlay on /home/spark - home directory may be read-only\n");
} else {
printf("Overlay filesystem mounted on /home/spark (writable user home)\n");
}
// Mount tmpfs on /run for runtime data
if (system("mkdir -p /run 2>/dev/null") == 0) {
if (system("mount -t tmpfs tmpfs /run 2>/dev/null") != 0) {
fprintf(stderr, "Warning: Failed to mount /run\n");
}
}
// Initialize network (wired only for bootstrap)
printf("Initializing wired network...\n");
if (system("/sbin/init-network 2>/dev/null") != 0) {
fprintf(stderr, "Warning: Network initialization failed - check network interface availability\n");
}
printf("Starting shell...\n");
printf("Welcome to SparkOS!\n");
printf("===================\n");
printf("Base OS: Read-only (immutable)\n");
printf("Writable: /tmp, /var (overlay), /home/spark (overlay), /run\n\n");
// Main loop - keep respawning shell
while (1) {
spawn_shell();
// If shell exits, ask if user wants to reboot
printf("\nShell exited. Press Ctrl+Alt+Del to reboot or wait for new shell...\n");
sleep(2);
}
return 0;
}