Remove busybox and CLI dependencies from init system and scripts

Co-authored-by: johndoe6345789 <224850594+johndoe6345789@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot]
2026-01-02 01:40:14 +00:00
parent 4facc3cb09
commit 35c236fe6b
5 changed files with 219 additions and 425 deletions

View File

@@ -23,9 +23,9 @@ FROM alpine:3.19
COPY scripts/docker-install-packages.sh /tmp/ COPY scripts/docker-install-packages.sh /tmp/
RUN /tmp/docker-install-packages.sh RUN /tmp/docker-install-packages.sh
# Alpine Linux includes BusyBox by default # SparkOS Philosophy: No CLI tools, GUI-only experience
# BusyBox provides: shell (sh), networking (udhcpc, ip, ping, wget), and core utilities # The init system is completely self-contained with no external dependencies
# This is verified by the test.sh script which shows BusyBox version and available applets # All functionality is provided through direct system calls in C
# Create minimal rootfs structure # Create minimal rootfs structure
COPY scripts/docker-setup-rootfs.sh /tmp/ COPY scripts/docker-setup-rootfs.sh /tmp/

View File

@@ -1,43 +1,41 @@
SparkOS Root Filesystem SparkOS Root Filesystem
======================= =======================
This is the root filesystem for SparkOS, a minimal Linux distribution. This is the root filesystem for SparkOS, a GUI-only Linux distribution.
Minimal System Packages: SparkOS Philosophy:
- Linux Kernel (with networking support) - GUI-Only: No CLI tools, no shell, no Unix utilities
- SparkOS Init System (custom) - Network-First: Networking integrated into Qt6 GUI
- Busybox (shell, utilities, networking) - Direct Kernel Interface: Qt6 communicates directly with Linux kernel
- Git (for installing spark CLI) - No Unix Baggage: No users, groups, passwords, or authentication
- Sudo (privilege elevation)
Minimal System:
- Linux Kernel (with networking and framebuffer support)
- SparkOS Init System (completely self-contained, no dependencies)
- Qt6 GUI Application (all user interaction)
Directory Structure: Directory Structure:
/bin, /sbin - Essential binaries /sbin - Init binary only
/etc - Configuration files /etc - Minimal configuration files
/proc, /sys, /dev - Kernel interfaces /proc, /sys, /dev - Kernel interfaces
/tmp - Temporary files /tmp - Temporary files
/usr - User programs /usr - Qt6 GUI application and libraries
/var - Variable data /var - Variable data (overlay mount)
/root - Root home directory /root - Root home directory
/home/spark - Default user home directory
Default User:
Username: spark (UID 1000)
Home: /home/spark
Sudo: Full access without password
Scripts: ~/clone-sparkos.sh for installing spark CLI
Network Configuration: Network Configuration:
/etc/network/interfaces - Wired network (DHCP) - Managed entirely through Qt6 GUI
/etc/resolv.conf - DNS configuration (8.8.8.8, 1.1.1.1) - Init brings up interfaces via direct ioctl calls
/sbin/init-network - Network initialization script - DHCP and network management handled by Qt6 NetworkManager
- /etc/resolv.conf provides fallback DNS servers
Bootstrap Process: Boot Process:
1. System boots as 'spark' user with wired networking (DHCP) 1. Linux kernel loads
2. Run ~/clone-sparkos.sh to install spark CLI 2. Init (PID 1) mounts filesystems
3. Use spark CLI to configure WiFi and system 3. Init brings up network interfaces
4. Install additional packages via spark CLI 4. Init spawns Qt6 GUI application
5. Use 'sudo' for any root-level operations 5. All user interaction through GUI
Note: This is a minimal system. You'll need to populate /bin and /usr/bin Note: This is a minimal, GUI-only system.
with actual binaries (busybox, git, sudo) from a proper Linux system No shell, no CLI tools, no busybox.
or by cross-compiling. All functionality is provided through the Qt6 GUI application.

View File

@@ -1,8 +1,7 @@
#!/bin/bash #!/bin/bash
# SparkOS Setup Script # SparkOS Setup Script
# Sets up a minimal rootfs with busybox and essential utilities # Sets up a minimal rootfs for GUI-only SparkOS
# Note: This script runs on the host system and uses bash for ${BASH_SOURCE} # Note: This script runs on the host system and uses bash for ${BASH_SOURCE}
# The target system uses busybox sh instead.
set -e set -e
@@ -16,16 +15,12 @@ echo ""
# Create directory structure # Create directory structure
echo "Creating directory structure..." echo "Creating directory structure..."
mkdir -p "$ROOTFS_DIR"/{bin,sbin,etc,proc,sys,dev,tmp,usr/{bin,sbin,lib,lib64},var,root,home} mkdir -p "$ROOTFS_DIR"/{sbin,etc,proc,sys,dev,tmp,usr/{bin,sbin,lib,lib64},var,root}
mkdir -p "$ROOTFS_DIR/etc"/{init.d,network}
mkdir -p "$ROOTFS_DIR/var"/{log,run} mkdir -p "$ROOTFS_DIR/var"/{log,run}
mkdir -p "$ROOTFS_DIR/home/spark"
mkdir -p "$ROOTFS_DIR/etc/sudoers.d"
# Set permissions # Set permissions
chmod 1777 "$ROOTFS_DIR/tmp" chmod 1777 "$ROOTFS_DIR/tmp"
chmod 700 "$ROOTFS_DIR/root" chmod 700 "$ROOTFS_DIR/root"
chmod 755 "$ROOTFS_DIR/home/spark"
# Create basic config files # Create basic config files
echo "Creating configuration files..." echo "Creating configuration files..."
@@ -40,19 +35,6 @@ cat > "$ROOTFS_DIR/etc/hosts" << 'EOF'
::1 localhost ip6-localhost ip6-loopback ::1 localhost ip6-localhost ip6-loopback
EOF EOF
# /etc/passwd
cat > "$ROOTFS_DIR/etc/passwd" << 'EOF'
root:x:0:0:root:/root:/bin/sh
spark:x:1000:1000:SparkOS User:/home/spark:/bin/sh
EOF
# /etc/group
cat > "$ROOTFS_DIR/etc/group" << 'EOF'
root:x:0:
spark:x:1000:
sudo:x:27:spark
EOF
# /etc/fstab # /etc/fstab
cat > "$ROOTFS_DIR/etc/fstab" << 'EOF' cat > "$ROOTFS_DIR/etc/fstab" << 'EOF'
# <file system> <mount point> <type> <options> <dump> <pass> # <file system> <mount point> <type> <options> <dump> <pass>
@@ -62,320 +44,77 @@ devtmpfs /dev devtmpfs defaults 0 0
tmpfs /tmp tmpfs defaults 0 0 tmpfs /tmp tmpfs defaults 0 0
EOF EOF
# /etc/resolv.conf - DNS configuration # /etc/resolv.conf - DNS configuration (managed by Qt6 GUI)
cat > "$ROOTFS_DIR/etc/resolv.conf" << 'EOF' cat > "$ROOTFS_DIR/etc/resolv.conf" << 'EOF'
# SparkOS DNS Configuration # SparkOS DNS Configuration
# Fallback to public DNS servers for reliability # Managed by Qt6 GUI NetworkManager
# Fallback to public DNS servers
nameserver 8.8.8.8 nameserver 8.8.8.8
nameserver 8.8.4.4 nameserver 8.8.4.4
nameserver 1.1.1.1 nameserver 1.1.1.1
nameserver 1.0.0.1 nameserver 1.0.0.1
EOF EOF
# /etc/sudoers - Sudo configuration
cat > "$ROOTFS_DIR/etc/sudoers" << 'EOF'
# SparkOS Sudoers Configuration
# Allow spark user to run any command without password
# Default settings
Defaults env_reset
Defaults secure_path="/bin:/sbin:/usr/bin:/usr/sbin"
# Root can run anything
root ALL=(ALL:ALL) ALL
# Spark user can run anything without password
spark ALL=(ALL:ALL) NOPASSWD: ALL
# Include sudoers.d directory
@includedir /etc/sudoers.d
EOF
chmod 0440 "$ROOTFS_DIR/etc/sudoers"
# /etc/network/interfaces - Wired network configuration
cat > "$ROOTFS_DIR/etc/network/interfaces" << 'EOF'
# SparkOS Network Configuration
# Wired networking only for bootstrapping
# Loopback interface
auto lo
iface lo inet loopback
# Primary wired interface (DHCP)
auto eth0
iface eth0 inet dhcp
EOF
# /etc/profile
cat > "$ROOTFS_DIR/etc/profile" << 'EOF'
# SparkOS System Profile
export PATH=/bin:/sbin:/usr/bin:/usr/sbin
export PS1='SparkOS:\w\$ '
export TERM=linux
# Set HOME based on user
if [ "$(id -u)" = "0" ]; then
export HOME=/root
else
export HOME=/home/$(whoami)
fi
# Welcome message
echo "Welcome to SparkOS!"
echo "Type 'help' for available commands"
echo ""
EOF
# Create .profile for root (busybox uses .profile instead of .bashrc)
cat > "$ROOTFS_DIR/root/.profile" << 'EOF'
# SparkOS Root Shell Configuration
# Set prompt
PS1='SparkOS:\w# '
# Aliases
alias ll='ls -lah'
alias ..='cd ..'
# Environment
export EDITOR=vi
export PAGER=less
EOF
# Create .profile for spark user
cat > "$ROOTFS_DIR/home/spark/.profile" << 'EOF'
# SparkOS User Shell Configuration
# Set prompt
PS1='SparkOS:\w\$ '
# Aliases
alias ll='ls -lah'
alias ..='cd ..'
# Environment
export EDITOR=vi
export PAGER=less
EOF
# Create clone-sparkos.sh script for spark user
cat > "$ROOTFS_DIR/home/spark/clone-sparkos.sh" << 'EOF'
#!/bin/sh
# SparkOS CLI Installation Script
# This script clones the SparkOS CLI repository
echo "SparkOS CLI Installation"
echo "========================"
echo ""
SPARK_REPO="https://github.com/johndoe6345789/spark-cli.git"
INSTALL_DIR="$HOME/spark-cli"
echo "This script will clone the SparkOS CLI to: $INSTALL_DIR"
echo ""
# Check if git is available
if ! command -v git >/dev/null 2>&1; then
echo "Error: git is not installed"
echo "Please install git to continue"
exit 1
fi
# Check if directory already exists
if [ -d "$INSTALL_DIR" ]; then
echo "Warning: $INSTALL_DIR already exists"
echo -n "Do you want to remove it and re-clone? (y/N): "
read answer
if [ "$answer" = "y" ] || [ "$answer" = "Y" ]; then
rm -rf "$INSTALL_DIR"
else
echo "Installation cancelled"
exit 0
fi
fi
# Clone the repository
echo "Cloning spark CLI repository..."
if git clone "$SPARK_REPO" "$INSTALL_DIR"; then
echo ""
echo "SparkOS CLI cloned successfully!"
echo ""
echo "Next steps:"
echo " 1. cd $INSTALL_DIR"
echo " 2. Follow the installation instructions in the repository"
echo ""
else
echo ""
echo "Error: Failed to clone repository"
echo "Please check your network connection and try again"
exit 1
fi
EOF
chmod +x "$ROOTFS_DIR/home/spark/clone-sparkos.sh"
# Create a simple help script
cat > "$ROOTFS_DIR/bin/sparkos-help" << 'EOF'
#!/bin/sh
cat << 'HELP'
SparkOS - Minimal Linux Distribution
====================================
Default Packages:
- Kernel (Linux)
- Init system (custom)
- Busybox (shell and utilities)
- Git (for installing spark CLI)
- Sudo (privilege elevation)
Default User:
Username: spark
Home: /home/spark
Privileges: Full sudo access (no password required)
To run commands as root: sudo <command>
To become root: sudo -i
Available commands:
ls, cd, pwd - Navigate filesystem
cat, less - View files
mkdir, rm, cp - File operations
mount, umount - Mount filesystems
ip, ifconfig - Network configuration
ping, wget - Network testing
git - Version control
sudo - Run commands as root
poweroff, reboot - System control
help - Show this help
Network:
Wired networking (eth0) configured via DHCP
DNS: 8.8.8.8, 1.1.1.1 (Google and Cloudflare)
To check network: ping 8.8.8.8
To test DNS: ping google.com
Next Steps:
1. Install spark CLI: ~/clone-sparkos.sh
2. Use spark CLI to configure WiFi and system
3. Install additional packages as needed
For more information: https://github.com/johndoe6345789/SparkOS
HELP
EOF
chmod +x "$ROOTFS_DIR/bin/sparkos-help"
ln -sf sparkos-help "$ROOTFS_DIR/bin/help"
# Create network initialization script
cat > "$ROOTFS_DIR/sbin/init-network" << 'EOF'
#!/bin/sh
# SparkOS Network Initialization
# Brings up wired networking for system bootstrap
echo "Initializing network..."
# Bring up loopback
ip link set lo up 2>/dev/null || ifconfig lo up 2>/dev/null
# Bring up primary wired interface with DHCP
# Try eth0 first, then other common interface names
for iface in eth0 enp0s3 enp0s8 ens33; do
if ip link show "$iface" >/dev/null 2>&1; then
echo "Bringing up $iface..."
# Bring up the interface
if ip link set "$iface" up 2>/dev/null || ifconfig "$iface" up 2>/dev/null; then
# Try to get IP via DHCP using busybox udhcpc
if command -v udhcpc >/dev/null 2>&1; then
# Run udhcpc in background, it will daemonize itself
udhcpc -i "$iface" -b -t 5 2>/dev/null
fi
else
echo "Warning: Failed to bring up $iface"
fi
break
fi
done
echo "Network initialization complete"
EOF
chmod +x "$ROOTFS_DIR/sbin/init-network"
# Create README # Create README
cat > "$ROOTFS_DIR/README.txt" << 'EOF' cat > "$ROOTFS_DIR/README.txt" << 'EOF'
SparkOS Root Filesystem SparkOS Root Filesystem
======================= =======================
This is the root filesystem for SparkOS, a minimal Linux distribution. This is the root filesystem for SparkOS, a GUI-only Linux distribution.
Minimal System Packages: SparkOS Philosophy:
- Linux Kernel (with networking support) - GUI-Only: No CLI tools, no shell, no Unix utilities
- SparkOS Init System (custom) - Network-First: Networking integrated into Qt6 GUI
- Busybox (shell, utilities, networking) - Direct Kernel Interface: Qt6 communicates directly with Linux kernel
- Git (for installing spark CLI) - No Unix Baggage: No users, groups, passwords, or authentication
- Sudo (privilege elevation)
Minimal System:
- Linux Kernel (with networking and framebuffer support)
- SparkOS Init System (completely self-contained, no dependencies)
- Qt6 GUI Application (all user interaction)
Directory Structure: Directory Structure:
/bin, /sbin - Essential binaries /sbin - Init binary only
/etc - Configuration files /etc - Minimal configuration files
/proc, /sys, /dev - Kernel interfaces /proc, /sys, /dev - Kernel interfaces
/tmp - Temporary files /tmp - Temporary files
/usr - User programs /usr - Qt6 GUI application and libraries
/var - Variable data /var - Variable data (overlay mount)
/root - Root home directory /root - Root home directory
/home/spark - Default user home directory
Default User:
Username: spark (UID 1000)
Home: /home/spark
Sudo: Full access without password
Scripts: ~/clone-sparkos.sh for installing spark CLI
Network Configuration: Network Configuration:
/etc/network/interfaces - Wired network (DHCP) - Managed entirely through Qt6 GUI
/etc/resolv.conf - DNS configuration (8.8.8.8, 1.1.1.1) - Init brings up interfaces via direct ioctl calls
/sbin/init-network - Network initialization script - DHCP and network management handled by Qt6 NetworkManager
- /etc/resolv.conf provides fallback DNS servers
Bootstrap Process: Boot Process:
1. System boots as 'spark' user with wired networking (DHCP) 1. Linux kernel loads
2. Run ~/clone-sparkos.sh to install spark CLI 2. Init (PID 1) mounts filesystems
3. Use spark CLI to configure WiFi and system 3. Init brings up network interfaces
4. Install additional packages via spark CLI 4. Init spawns Qt6 GUI application
5. Use 'sudo' for any root-level operations 5. All user interaction through GUI
Note: This is a minimal system. You'll need to populate /bin and /usr/bin Note: This is a minimal, GUI-only system.
with actual binaries (busybox, git, sudo) from a proper Linux system No shell, no CLI tools, no busybox.
or by cross-compiling. All functionality is provided through the Qt6 GUI application.
EOF EOF
echo "" echo ""
echo "Root filesystem structure created at: $ROOTFS_DIR" echo "Root filesystem structure created at: $ROOTFS_DIR"
echo "" echo ""
echo "User configuration:" echo "SparkOS Configuration:"
echo " - Default user: spark (UID 1000)" echo " - Architecture: GUI-only, no CLI"
echo " - Home directory: /home/spark" echo " - Init: Self-contained, no external dependencies"
echo " - Sudo access: Enabled (no password required)" echo " - Network: Direct C implementation via ioctl"
echo " - Clone script: /home/spark/clone-sparkos.sh" echo " - User Experience: Pure Qt6 GUI"
echo ""
echo "Network configuration:"
echo " - Wired networking (DHCP) configured for eth0"
echo " - DNS: 8.8.8.8, 1.1.1.1, 8.8.4.4, 1.0.0.1"
echo " - Network init script: /sbin/init-network"
echo "" echo ""
echo "Next steps:" echo "Next steps:"
echo " 1. Build init: make init" echo " 1. Build init: make init"
echo " 2. Install init: make install" echo " 2. Install init: make install"
echo " 3. Copy busybox, git, and sudo binaries to rootfs/bin/" echo " 3. Build Qt6 GUI: make gui"
echo " 4. Create busybox symlinks" echo " 4. Create bootable image: sudo make image"
echo " 5. Create bootable image: sudo make image"
echo "" echo ""
echo "Minimum required binaries:" echo "Philosophy:"
echo " - busybox (provides shell, networking, utilities)" echo " No busybox, no shell, no CLI tools"
echo " - git (for installing spark CLI)" echo " Everything is GUI-driven through Qt6"
echo " - sudo (for privilege elevation)"
echo ""
echo "Note: Busybox should be compiled with networking support"
echo " (CONFIG_UDHCPC, CONFIG_IFCONFIG, CONFIG_IP, CONFIG_PING, CONFIG_WGET)"

View File

@@ -3,48 +3,6 @@ echo "SparkOS Docker Test Environment"
echo "================================" echo "================================"
echo "" echo ""
# Verify BusyBox is present and working
echo "Verifying BusyBox..."
echo "-------------------"
if command -v busybox >/dev/null 2>&1; then
echo "✓ BusyBox is installed"
echo ""
echo "BusyBox version:"
# Store version for reuse in summary
BUSYBOX_VERSION=$(busybox | head -n 1)
echo "$BUSYBOX_VERSION"
echo ""
echo "BusyBox location:"
which busybox
ls -lh "$(which busybox)"
echo ""
echo "Shell (/bin/sh) is BusyBox:"
ls -lh /bin/sh
if [ -L /bin/sh ]; then
echo " → /bin/sh is a symlink to: \"$(readlink /bin/sh)\""
fi
echo ""
echo "Available BusyBox applets (sample):"
# Store applet list once to avoid redundant executions
APPLET_LIST=$(busybox --list)
echo "$APPLET_LIST" | head -n 20
echo " ... and $(echo "$APPLET_LIST" | wc -l) total applets"
echo ""
echo "Networking applets (required for SparkOS):"
for cmd in udhcpc ip ifconfig ping wget; do
if echo "$APPLET_LIST" | grep -q "^${cmd}$"; then
echo "$cmd"
else
echo "$cmd (NOT FOUND)"
fi
done
else
echo "✗ BusyBox not found!"
echo " SparkOS requires BusyBox for shell and utilities"
exit 1
fi
echo ""
echo "Verifying SparkOS init binary..." echo "Verifying SparkOS init binary..."
echo "--------------------------------" echo "--------------------------------"
if [ -f /sparkos/rootfs/sbin/init ]; then if [ -f /sparkos/rootfs/sbin/init ]; then
@@ -75,10 +33,13 @@ echo "✓ SparkOS is ready for testing!"
echo "================================" echo "================================"
echo "" echo ""
echo "Summary:" echo "Summary:"
echo " - BusyBox: $BUSYBOX_VERSION" echo " - Init: Custom SparkOS init system (no external dependencies)"
echo " - Init: Custom SparkOS init system" echo " - Architecture: GUI-only, no CLI/shell"
echo " - Shell: BusyBox sh (/bin/sh)" echo " - Network: Direct C implementation via ioctl"
echo " - Networking: BusyBox udhcpc, ip, ping, wget" echo " - Philosophy: Pure GUI experience, network-first"
echo ""
echo "Note: SparkOS has no CLI tools (no busybox, no shell)"
echo " All functionality is provided through the Qt6 GUI"
echo "" echo ""
echo "To test the init system:" echo "To test the init system:"
echo " docker run --rm <image> /sparkos/rootfs/sbin/init --help" echo " docker run --rm <image> /sparkos/rootfs/sbin/init"

View File

@@ -1,6 +1,11 @@
/* /*
* SparkOS Init - Minimal init system for SparkOS * SparkOS Init - Minimal init system for SparkOS
* This is the first process that runs after the kernel boots * This is the first process that runs after the kernel boots
*
* SparkOS Philosophy: GUI-only, no CLI, network-first
* - No shell spawning or CLI utilities
* - Direct boot to Qt6 GUI
* - Network initialization via direct C system calls
*/ */
#include <stdio.h> #include <stdio.h>
@@ -8,9 +13,16 @@
#include <unistd.h> #include <unistd.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <sys/reboot.h> #include <sys/reboot.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <net/if.h>
#include <linux/if.h>
#include <signal.h> #include <signal.h>
#include <errno.h> #include <errno.h>
#include <string.h> #include <string.h>
#include <arpa/inet.h>
static void signal_handler(int sig) { static void signal_handler(int sig) {
if (sig == SIGCHLD) { if (sig == SIGCHLD) {
@@ -33,7 +45,7 @@ static void spawn_gui() {
char *argv[] = {"/usr/bin/sparkos-gui", NULL}; char *argv[] = {"/usr/bin/sparkos-gui", NULL};
char *envp[] = { char *envp[] = {
"HOME=/root", "HOME=/root",
"PATH=/bin:/sbin:/usr/bin:/usr/sbin", "PATH=/usr/bin:/usr/sbin",
"QT_QPA_PLATFORM=linuxfb:fb=/dev/fb0", "QT_QPA_PLATFORM=linuxfb:fb=/dev/fb0",
"QT_QPA_FB_FORCE_FULLSCREEN=1", "QT_QPA_FB_FORCE_FULLSCREEN=1",
"QT_QPA_FONTDIR=/usr/share/fonts", "QT_QPA_FONTDIR=/usr/share/fonts",
@@ -51,39 +63,122 @@ static void spawn_gui() {
waitpid(pid, &status, 0); waitpid(pid, &status, 0);
} }
static void spawn_shell() { /*
pid_t pid = fork(); * Initialize network interface directly via ioctl
* No dependency on busybox or CLI tools
*/
static int init_network_interface(const char *ifname) {
int sock;
struct ifreq ifr;
if (pid < 0) { // Create socket for ioctl operations
perror("fork failed"); sock = socket(AF_INET, SOCK_DGRAM, 0);
return; if (sock < 0) {
perror("socket creation failed");
return -1;
} }
if (pid == 0) { // Prepare interface request structure
// Child process - exec shell as root (fallback only) memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, ifname, IFNAMSIZ - 1);
char *argv[] = {"/bin/sh", "-l", NULL};
char *envp[] = { // Get current flags
"HOME=/root", if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) {
"PATH=/bin:/sbin:/usr/bin:/usr/sbin", close(sock);
"TERM=linux", return -1; // Interface doesn't exist
"PS1=SparkOS# ",
NULL
};
execve("/bin/sh", argv, envp);
perror("failed to exec shell");
exit(1);
} }
// Parent process - wait for shell to exit // Bring interface up
int status; ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
waitpid(pid, &status, 0); if (ioctl(sock, SIOCSIFFLAGS, &ifr) < 0) {
perror("failed to bring up interface");
close(sock);
return -1;
}
close(sock);
printf("Network interface %s brought up successfully\n", ifname);
return 0;
}
/*
* Initialize networking without external dependencies
* Brings up loopback and first available ethernet interface
*/
static void init_network() {
const char *interfaces[] = {"lo", "eth0", "enp0s3", "enp0s8", "ens33", NULL};
int i;
int eth_initialized = 0;
printf("Initializing network interfaces...\n");
// Bring up loopback
if (init_network_interface("lo") == 0) {
printf("Loopback interface initialized\n");
}
// Try to bring up first available ethernet interface
for (i = 1; interfaces[i] != NULL && !eth_initialized; i++) {
if (init_network_interface(interfaces[i]) == 0) {
printf("Primary network interface %s initialized\n", interfaces[i]);
printf("Note: DHCP configuration should be handled by Qt6 GUI\n");
eth_initialized = 1;
}
}
if (!eth_initialized) {
fprintf(stderr, "Warning: No ethernet interface found or initialized\n");
fprintf(stderr, "Network configuration will be available through GUI\n");
}
}
/*
* Mount filesystem using direct mount() system call
* No dependency on mount binary
*/
static int mount_fs(const char *source, const char *target, const char *fstype, unsigned long flags) {
if (mount(source, target, fstype, flags, NULL) < 0) {
return -1;
}
return 0;
}
/*
* Create directory recursively
* No dependency on mkdir binary
*/
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) {
return -1;
}
*p = '/';
}
}
if (mkdir(tmp, 0755) < 0 && errno != EEXIST) {
return -1;
}
return 0;
} }
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
printf("SparkOS Init System Starting...\n"); printf("SparkOS Init System Starting...\n");
printf("================================\n");
printf("Philosophy: GUI-Only, No CLI, Network-First\n");
printf("================================\n\n");
// Make sure we're PID 1 // Make sure we're PID 1
if (getpid() != 1) { if (getpid() != 1) {
@@ -94,18 +189,18 @@ int main(int argc, char *argv[]) {
// Set up signal handlers // Set up signal handlers
signal(SIGCHLD, signal_handler); signal(SIGCHLD, signal_handler);
// Mount essential filesystems // Mount essential filesystems using direct system calls
printf("Mounting essential filesystems...\n"); printf("Mounting essential filesystems...\n");
if (system("mount -t proc proc /proc 2>/dev/null") != 0) { if (mount_fs("proc", "/proc", "proc", 0) != 0) {
fprintf(stderr, "Warning: Failed to mount /proc\n"); fprintf(stderr, "Warning: Failed to mount /proc\n");
} }
if (system("mount -t sysfs sys /sys 2>/dev/null") != 0) { if (mount_fs("sysfs", "/sys", "sysfs", 0) != 0) {
fprintf(stderr, "Warning: Failed to mount /sys\n"); fprintf(stderr, "Warning: Failed to mount /sys\n");
} }
if (system("mount -t devtmpfs dev /dev 2>/dev/null") != 0) { if (mount_fs("devtmpfs", "/dev", "devtmpfs", 0) != 0) {
fprintf(stderr, "Warning: Failed to mount /dev\n"); fprintf(stderr, "Warning: Failed to mount /dev\n");
} }
if (system("mount -t tmpfs tmpfs /tmp 2>/dev/null") != 0) { if (mount_fs("tmpfs", "/tmp", "tmpfs", 0) != 0) {
fprintf(stderr, "Warning: Failed to mount /tmp\n"); fprintf(stderr, "Warning: Failed to mount /tmp\n");
} }
@@ -113,37 +208,38 @@ int main(int argc, char *argv[]) {
printf("Setting up overlay filesystem for writable layer...\n"); printf("Setting up overlay filesystem for writable layer...\n");
// Create overlay directories in tmpfs // Create overlay directories in tmpfs
if (system("mkdir -p /tmp/overlay/var-upper /tmp/overlay/var-work 2>/dev/null") != 0) { if (mkdir_p("/tmp/overlay/var-upper") != 0 || mkdir_p("/tmp/overlay/var-work") != 0) {
fprintf(stderr, "Warning: Failed to create overlay directories for /var\n"); fprintf(stderr, "Warning: Failed to create overlay directories for /var\n");
} }
// Mount overlay on /var for logs and runtime data // 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) { char overlay_opts[256];
snprintf(overlay_opts, sizeof(overlay_opts),
"lowerdir=/var,upperdir=/tmp/overlay/var-upper,workdir=/tmp/overlay/var-work");
if (mount("overlay", "/var", "overlay", 0, overlay_opts) != 0) {
fprintf(stderr, "Warning: Failed to mount overlay on /var - system may be read-only\n"); fprintf(stderr, "Warning: Failed to mount overlay on /var - system may be read-only\n");
} else { } else {
printf("Overlay filesystem mounted on /var (base OS is immutable)\n"); printf("Overlay filesystem mounted on /var (base OS is immutable)\n");
} }
// Mount tmpfs on /run for runtime data // Mount tmpfs on /run for runtime data
if (system("mkdir -p /run 2>/dev/null") == 0) { if (mkdir_p("/run") == 0) {
if (system("mount -t tmpfs tmpfs /run 2>/dev/null") != 0) { if (mount_fs("tmpfs", "/run", "tmpfs", 0) != 0) {
fprintf(stderr, "Warning: Failed to mount /run\n"); fprintf(stderr, "Warning: Failed to mount /run\n");
} }
} }
// Initialize network (wired only for bootstrap) // Initialize network interfaces
printf("Initializing wired network...\n"); init_network();
if (system("/sbin/init-network 2>/dev/null") != 0) {
fprintf(stderr, "Warning: Network initialization failed - check network interface availability\n");
}
printf("Starting Qt6 GUI application...\n"); printf("\nStarting Qt6 GUI application...\n");
printf("Welcome to SparkOS!\n"); printf("Welcome to SparkOS!\n");
printf("===================\n"); printf("===================\n");
printf("Base OS: Read-only (immutable)\n"); printf("Base OS: Read-only (immutable)\n");
printf("Writable: /tmp, /var (overlay), /run\n"); printf("Writable: /tmp, /var (overlay), /run\n");
printf("Mode: Qt6 GUI (Network-First Architecture)\n"); printf("Mode: Qt6 GUI (Network-First Architecture)\n");
printf("No Users/Authentication - Direct Boot to GUI\n\n"); printf("No Users/Authentication - Direct Boot to GUI\n");
printf("No CLI/Shell - Pure GUI Experience\n\n");
// Main loop - keep respawning GUI application // Main loop - keep respawning GUI application
while (1) { while (1) {