diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 032bc0c..e758f3b 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -2,121 +2,88 @@ ## Overview -SparkOS is designed as a minimal Linux distribution with a custom init system and a modular architecture that allows for future expansion. +SparkOS is a revolutionary operating system that uses the Linux kernel for hardware abstraction but ditches traditional Unix conventions. Instead of shells, users, and Unix utilities, SparkOS boots directly into a Qt6 GUI that interfaces with the kernel through standard Linux APIs. -## System Components +## Core Philosophy -### 1. Init System (`/sbin/init`) +1. **No Unix Baggage**: No user/group system, no shells, no Unix utilities by default +2. **Direct Kernel Interface**: GUI communicates directly with Linux kernel +3. **Network-First**: Networking is a primary interface, not an afterthought +4. **GUI-Only**: No CLI unless explicitly needed for debugging +5. **Linux for Drivers**: Leverage Linux's excellent hardware support -The init system is the first process started by the kernel (PID 1). It is responsible for: - -- **Mounting filesystems**: proc, sys, dev, tmp -- **Network initialization**: Bringing up wired networking via DHCP -- **Process management**: Spawning and respawning the shell -- **Signal handling**: Reaping zombie processes -- **System initialization**: Setting up the initial environment - -**Implementation**: `src/init.c` -- Written in C for minimal overhead -- Statically linked for independence -- ~100 lines of clean, well-documented code - -### 2. Root Filesystem - -Follows the Filesystem Hierarchy Standard (FHS): +## System Architecture ``` -/ -├── bin/ Essential user binaries (busybox with symlinks) -├── sbin/ System binaries (init, mount, etc.) -├── etc/ System configuration files -├── proc/ Kernel process information (virtual) -├── sys/ Kernel system information (virtual) -├── dev/ Device files (virtual) -├── tmp/ Temporary files -├── usr/ -│ ├── bin/ Non-essential user binaries -│ ├── sbin/ Non-essential system binaries -│ ├── lib/ Libraries for /usr/bin and /usr/sbin -│ └── lib64/ 64-bit libraries -├── var/ Variable data (logs, caches) -├── root/ Root user home directory -└── home/ User home directories -``` +Boot Sequence: +Hardware → UEFI/BIOS → GRUB → Linux Kernel → init (PID 1) → Qt6 GUI -### 3. Build System - -**Makefile**: Main build orchestration -- `make init`: Compile init system -- `make install`: Install init to rootfs -- `make image`: Create bootable image (requires root) -- `make clean`: Clean build artifacts - -**Scripts**: -- `scripts/build.sh`: Quick build for development -- `scripts/setup_rootfs.sh`: Create rootfs structure -- `scripts/create_image.sh`: Create dd-able disk image - -### 4. Boot Process - -``` -Hardware Power-On - ↓ -BIOS/UEFI - ↓ -Bootloader (syslinux) - ↓ -Linux Kernel (vmlinuz) - ↓ -Init System (/sbin/init) [PID 1] - ↓ -Mount filesystems - ↓ -Initialize network (/sbin/init-network) - ↓ -Spawn busybox sh shell - ↓ -User interaction +Stack Layers: +┌──────────────────────────────────────────┐ +│ Qt6 GUI Application │ ← User Interface +│ (sparkos-gui executable) │ +├──────────────────────────────────────────┤ +│ Custom Init System (PID 1) │ ← Process Manager +│ • Mounts filesystems │ +│ • Spawns/respawns GUI │ +│ • Reaps zombie processes │ +├──────────────────────────────────────────┤ +│ Linux Kernel │ ← Hardware Abstraction +│ • All device drivers │ +│ • Framebuffer driver │ +│ • Input device drivers │ +│ • Network stack & drivers │ +│ • File system support │ +├──────────────────────────────────────────┤ +│ Hardware │ +│ • Display, GPU, Input │ +│ • Network adapters │ +│ • Storage devices │ +└──────────────────────────────────────────┘ ``` ## Design Decisions -### Why Custom Init? +### Why Ditch Unix Conventions? -- **Simplicity**: No dependencies, easy to understand -- **Control**: Full control over boot process -- **Size**: Minimal footprint (<1MB statically linked) -- **Learning**: Educational value for OS development +Traditional Unix systems were designed for multi-user, time-sharing mainframes in the 1970s. Modern personal computing and embedded systems have different needs: -### Why Static Linking? +- **Single User**: Most devices have one user - authentication overhead is unnecessary +- **GUI Primary**: Modern users expect graphical interfaces, not command lines +- **Network Central**: Modern computing is network-centric, not file-centric +- **Direct Access**: Applications should talk directly to kernel, not through layers of abstraction -- **Independence**: No library dependencies -- **Portability**: Works on any Linux system -- **Reliability**: No missing library issues +### Why Keep Linux Kernel? -### Why Busybox? +- **Hardware Support**: Linux has exceptional driver support for modern hardware +- **Driver Abstraction**: Well-tested, stable hardware abstraction layer +- **Network Stack**: Robust, high-performance networking +- **File Systems**: Mature support for various filesystems +- **Security**: SELinux, namespaces, cgroups for isolation +- **Community**: Active development and security updates -- **Minimal**: Single binary provides dozens of utilities -- **Small footprint**: Typically <1MB for full feature set -- **Efficient**: Less memory and storage overhead than full GNU coreutils -- **Standard**: De facto standard for embedded Linux systems -- **Networking**: Includes DHCP client (udhcpc), ping, wget, and network tools +### Why Qt6 GUI? -### Networking Strategy +- **Cross-Platform**: Qt works on many platforms (future portability) +- **Framebuffer Support**: Can render directly to Linux framebuffer without X11/Wayland +- **Modern**: Native look and feel, hardware acceleration support +- **Complete**: Rich widget set, networking APIs, file I/O +- **Performant**: Efficient rendering and event handling -SparkOS uses a two-phase networking approach: +### Why No X11/Wayland? -**Phase 1: Bootstrap (Wired Only)** -- Wired networking configured via DHCP -- Automatic interface detection (eth0, enp0s3, etc.) -- DNS fallback to public servers (8.8.8.8, 1.1.1.1) -- Enables git clone to install spark CLI +- **Direct Rendering**: Qt can render directly to framebuffer (/dev/fb0) +- **Less Overhead**: No display server running in between +- **Simpler**: Fewer processes, less memory usage +- **Embedded-Friendly**: Same approach used in embedded systems -**Phase 2: Full Configuration (via spark CLI)** -- WiFi configuration -- Advanced networking features -- Custom DNS settings -- Network profiles +### Why Network-First? + +Modern computing is inherently networked. Instead of treating networking as an add-on: +- Network APIs exposed directly to GUI +- Cloud storage as primary storage paradigm +- Web technologies integrated (future: embedded browser) +- Real-time updates and communication built-in ## Future Architecture diff --git a/Makefile b/Makefile index a0f37dc..ce928de 100644 --- a/Makefile +++ b/Makefile @@ -7,16 +7,18 @@ DESTDIR = rootfs IMAGE = sparkos.img IMAGE_SIZE = 512M -.PHONY: all clean init image image-docker help install docker-release +.PHONY: all clean init gui image image-docker help install docker-release -all: init +all: init gui help: @echo "SparkOS Build System" @echo "====================" @echo "Targets:" @echo " make init - Build the init system" - @echo " make install - Install init to rootfs" + @echo " make gui - Build the Qt6 GUI application" + @echo " make all - Build both init and GUI (default)" + @echo " make install - Install init and GUI to rootfs" @echo " make image - Create bootable dd-able image (requires root)" @echo " make image-docker - Create bootable image using Docker (no root required)" @echo " make docker-release - Build release package using Docker (no root required)" @@ -34,10 +36,20 @@ init: src/init.c $(CC) $(CFLAGS) -o init src/init.c @echo "Init system built successfully: ./init" -install: init +gui: + @echo "Building SparkOS Qt6 GUI application..." + @mkdir -p build/gui + @cd build/gui && cmake ../../src/qt6-app -DCMAKE_INSTALL_PREFIX=$(DESTDIR)/usr + @cd build/gui && $(MAKE) + @echo "Qt6 GUI application built successfully: build/gui/sparkos-gui" + +install: init gui @echo "Installing init to rootfs..." install -D -m 755 init $(DESTDIR)/sbin/init @echo "Init installed to $(DESTDIR)/sbin/init" + @echo "Installing Qt6 GUI application to rootfs..." + @cd build/gui && $(MAKE) install + @echo "GUI application installed to $(DESTDIR)/usr/bin/sparkos-gui" image: install @echo "Creating bootable image..." diff --git a/README.md b/README.md index c2bee96..a1372b1 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,46 @@ # SparkOS -A minimal Linux distribution designed for simplicity and portability. SparkOS features: +A revolutionary operating system that ditches Unix conventions for a modern, network-first approach. SparkOS features: -- **Minimal footprint**: Barebones Linux system with busybox shell +- **Direct Kernel Interface**: Qt6 GUI communicates directly with Linux kernel, bypassing Unix layers +- **Linux Driver Layer**: All hardware abstraction handled by Linux kernel drivers +- **No Unix User System**: No users, groups, passwords, or authentication - direct boot to GUI +- **Network-First Architecture**: Built around networking as the primary paradigm +- **Qt6 Full-Screen GUI**: Modern graphical interface from boot +- **Minimal footprint**: Lean system with only essential components - **Portable**: dd-able disk image for USB flash drives -- **Custom init**: Lightweight C init system -- **Future-ready**: Designed to support Qt6/QML GUI and Wayland -- **Root elevation**: Uses sudo for privilege management -- **Bootstrap networking**: Wired networking with DHCP for initial setup -- Minimal installation by default: kernel, init system, busybox, git, and sudo -- DNS configured with fallback to public DNS servers (8.8.8.8, 1.1.1.1) -- WiFi and advanced networking configured later via spark CLI +- **Custom init**: Lightweight C init system that launches GUI directly +- **Immutable base**: Read-only root filesystem with overlay for runtime data + +## Architecture + +``` +┌─────────────────────────────────────┐ +│ Qt6 GUI Application │ +│ (Direct Framebuffer Rendering) │ +└─────────────────────────────────────┘ + ↕ +┌─────────────────────────────────────┐ +│ Linux Kernel │ +│ • Framebuffer (/dev/fb0) │ +│ • Input devices (/dev/input/*) │ +│ • Network stack │ +│ • All hardware drivers │ +└─────────────────────────────────────┘ + ↕ +┌─────────────────────────────────────┐ +│ Hardware │ +│ • GPU, Display, Input devices │ +│ • Network adapters │ +│ • Storage, etc. │ +└─────────────────────────────────────┘ +``` + +**Key Design Principles:** +- Linux kernel provides complete hardware abstraction and driver support +- Qt6 interfaces directly with kernel through /dev, /proc, /sys interfaces +- No intermediate Unix layers (no systemd, no user management, no shells by default) +- Network-first: networking capabilities exposed directly to GUI ## MVP Status diff --git a/rootfs/etc/group b/rootfs/etc/group deleted file mode 100644 index d027b5e..0000000 --- a/rootfs/etc/group +++ /dev/null @@ -1,3 +0,0 @@ -root:x:0: -spark:x:1000: -sudo:x:27:spark diff --git a/rootfs/etc/passwd b/rootfs/etc/passwd deleted file mode 100644 index c2b6d42..0000000 --- a/rootfs/etc/passwd +++ /dev/null @@ -1,2 +0,0 @@ -root:x:0:0:root:/root:/bin/sh -spark:x:1000:1000:SparkOS User:/home/spark:/bin/sh diff --git a/rootfs/etc/sudoers b/rootfs/etc/sudoers deleted file mode 100644 index 73d4f07..0000000 --- a/rootfs/etc/sudoers +++ /dev/null @@ -1,15 +0,0 @@ -# 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 diff --git a/src/init.c b/src/init.c index cbf5d68..62baff8 100644 --- a/src/init.c +++ b/src/init.c @@ -12,12 +12,6 @@ #include #include -// 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 @@ -25,6 +19,38 @@ static void signal_handler(int sig) { } } +static void spawn_gui() { + pid_t pid = fork(); + + if (pid < 0) { + perror("fork failed"); + return; + } + + if (pid == 0) { + // Child process - exec Qt6 GUI application as root (no user switching) + + char *argv[] = {"/usr/bin/sparkos-gui", NULL}; + char *envp[] = { + "HOME=/root", + "PATH=/bin:/sbin:/usr/bin:/usr/sbin", + "QT_QPA_PLATFORM=linuxfb:fb=/dev/fb0", + "QT_QPA_FB_FORCE_FULLSCREEN=1", + "QT_QPA_FONTDIR=/usr/share/fonts", + NULL + }; + + execve("/usr/bin/sparkos-gui", argv, envp); + + perror("failed to exec GUI application"); + exit(1); + } + + // Parent process - wait for GUI to exit + int status; + waitpid(pid, &status, 0); +} + static void spawn_shell() { pid_t pid = fork(); @@ -34,34 +60,17 @@ static void spawn_shell() { } 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); - } + // Child process - exec shell as root (fallback only) char *argv[] = {"/bin/sh", "-l", NULL}; char *envp[] = { - "HOME=" SPARK_HOME, + "HOME=/root", "PATH=/bin:/sbin:/usr/bin:/usr/sbin", "TERM=linux", - "PS1=SparkOS$ ", - "USER=" SPARK_USER, - "LOGNAME=" SPARK_USER, + "PS1=SparkOS# ", NULL }; - // Change to home directory - if (chdir(SPARK_HOME) != 0) { - perror("chdir failed"); - } - execve("/bin/sh", argv, envp); perror("failed to exec shell"); @@ -107,9 +116,6 @@ int main(int argc, char *argv[]) { 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) { @@ -118,13 +124,6 @@ int main(int argc, char *argv[]) { 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) { @@ -138,18 +137,20 @@ int main(int argc, char *argv[]) { fprintf(stderr, "Warning: Network initialization failed - check network interface availability\n"); } - printf("Starting shell...\n"); + printf("Starting Qt6 GUI application...\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"); + printf("Writable: /tmp, /var (overlay), /run\n"); + printf("Mode: Qt6 GUI (Network-First Architecture)\n"); + printf("No Users/Authentication - Direct Boot to GUI\n\n"); - // Main loop - keep respawning shell + // Main loop - keep respawning GUI application while (1) { - spawn_shell(); + spawn_gui(); - // If shell exits, ask if user wants to reboot - printf("\nShell exited. Press Ctrl+Alt+Del to reboot or wait for new shell...\n"); + // If GUI exits, respawn after a short delay + printf("\nGUI application exited. Restarting in 2 seconds...\n"); sleep(2); } diff --git a/src/qt6-app/CMakeLists.txt b/src/qt6-app/CMakeLists.txt new file mode 100644 index 0000000..31c699d --- /dev/null +++ b/src/qt6-app/CMakeLists.txt @@ -0,0 +1,42 @@ +cmake_minimum_required(VERSION 3.16) + +project(sparkos-gui VERSION 1.0.0 LANGUAGES CXX) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +# Set build type to Release if not specified +if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE Release) +endif() + +# Find Qt6 packages +find_package(Qt6 REQUIRED COMPONENTS Core Widgets Gui) + +# Enable automatic MOC (Meta-Object Compiler) +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) +set(CMAKE_AUTOUIC ON) + +# Source files +set(SOURCES + main.cpp +) + +# Create executable +add_executable(sparkos-gui ${SOURCES}) + +# Link Qt6 libraries +target_link_libraries(sparkos-gui PRIVATE + Qt6::Core + Qt6::Widgets + Qt6::Gui +) + +# Set properties for static linking if desired +# target_link_options(sparkos-gui PRIVATE -static-libgcc -static-libstdc++) + +# Install target +install(TARGETS sparkos-gui + RUNTIME DESTINATION bin +) diff --git a/src/qt6-app/main.cpp b/src/qt6-app/main.cpp new file mode 100644 index 0000000..5c4dc8e --- /dev/null +++ b/src/qt6-app/main.cpp @@ -0,0 +1,186 @@ +/* + * SparkOS Qt6 GUI Application + * Direct kernel interface - bypassing Unix conventions + * Network-first, GUI-only operating system + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class SparkOSMainWindow : public QWidget { + Q_OBJECT + +public: + SparkOSMainWindow(QWidget *parent = nullptr) : QWidget(parent) { + setupUI(); + } + +private slots: + void showSystemInfo() { + // Direct kernel interface through /proc and /sys + QString info = "SparkOS - Direct Kernel Interface\n"; + info += "==================================\n\n"; + + // Read kernel version directly from /proc + QFile kernelFile("/proc/version"); + if (kernelFile.open(QIODevice::ReadOnly)) { + info += "Kernel: " + QString(kernelFile.readLine()).trimmed() + "\n\n"; + kernelFile.close(); + } + + // Read memory info directly from /proc + QFile meminfoFile("/proc/meminfo"); + if (meminfoFile.open(QIODevice::ReadOnly)) { + info += "Memory Info:\n"; + int lineCount = 0; + while (!meminfoFile.atEnd() && lineCount < 3) { + info += " " + QString(meminfoFile.readLine()).trimmed() + "\n"; + lineCount++; + } + meminfoFile.close(); + } + + info += "\n"; + info += "Architecture: Network-First OS\n"; + info += "No Unix user/group system\n"; + info += "Direct Qt6 GUI to Kernel interface\n"; + + QTextEdit *infoDialog = new QTextEdit(); + infoDialog->setReadOnly(true); + infoDialog->setPlainText(info); + infoDialog->setWindowTitle("System Information"); + infoDialog->resize(600, 400); + infoDialog->show(); + } + +private: + void setupUI() { + // Set window properties + setWindowTitle("SparkOS"); + + // Create main layout + QVBoxLayout *mainLayout = new QVBoxLayout(this); + mainLayout->setAlignment(Qt::AlignCenter); + mainLayout->setSpacing(30); + + // Create welcome label + QLabel *titleLabel = new QLabel("Welcome to SparkOS", this); + QFont titleFont; + titleFont.setPointSize(48); + titleFont.setBold(true); + titleLabel->setFont(titleFont); + titleLabel->setAlignment(Qt::AlignCenter); + titleLabel->setStyleSheet("color: #2196F3;"); + + // Create subtitle label + QLabel *subtitleLabel = new QLabel("Direct Kernel • Network-First • No Unix", this); + QFont subtitleFont; + subtitleFont.setPointSize(24); + subtitleLabel->setFont(subtitleFont); + subtitleLabel->setAlignment(Qt::AlignCenter); + subtitleLabel->setStyleSheet("color: #666;"); + + // Create status label + QLabel *statusLabel = new QLabel("✓ System Initialized • GUI Active", this); + QFont statusFont; + statusFont.setPointSize(16); + statusLabel->setFont(statusFont); + statusLabel->setAlignment(Qt::AlignCenter); + statusLabel->setStyleSheet("color: #4CAF50;"); + + // Create info label + QLabel *infoLabel = new QLabel("Qt6 GUI ↔ Linux Kernel (Direct Interface)", this); + QFont infoFont; + infoFont.setPointSize(14); + infoLabel->setFont(infoFont); + infoLabel->setAlignment(Qt::AlignCenter); + infoLabel->setStyleSheet("color: #999;"); + + // Create system info button + QPushButton *infoButton = new QPushButton("System Info", this); + infoButton->setMinimumSize(200, 60); + QFont buttonFont; + buttonFont.setPointSize(16); + infoButton->setFont(buttonFont); + infoButton->setStyleSheet( + "QPushButton {" + " background-color: #2196F3;" + " color: white;" + " border: none;" + " border-radius: 5px;" + " padding: 10px;" + "}" + "QPushButton:hover {" + " background-color: #1976D2;" + "}" + "QPushButton:pressed {" + " background-color: #0D47A1;" + "}" + ); + connect(infoButton, &QPushButton::clicked, this, &SparkOSMainWindow::showSystemInfo); + + // Create exit button + QPushButton *exitButton = new QPushButton("Power Off", this); + exitButton->setMinimumSize(200, 60); + exitButton->setFont(buttonFont); + exitButton->setStyleSheet( + "QPushButton {" + " background-color: #f44336;" + " color: white;" + " border: none;" + " border-radius: 5px;" + " padding: 10px;" + "}" + "QPushButton:hover {" + " background-color: #da190b;" + "}" + "QPushButton:pressed {" + " background-color: #a31408;" + "}" + ); + + // Connect exit button + connect(exitButton, &QPushButton::clicked, this, &QApplication::quit); + + // Add widgets to layout + mainLayout->addStretch(); + mainLayout->addWidget(titleLabel); + mainLayout->addWidget(subtitleLabel); + mainLayout->addSpacing(40); + mainLayout->addWidget(statusLabel); + mainLayout->addWidget(infoLabel); + mainLayout->addSpacing(40); + mainLayout->addWidget(infoButton, 0, Qt::AlignCenter); + mainLayout->addWidget(exitButton, 0, Qt::AlignCenter); + mainLayout->addStretch(); + + // Set background color + setStyleSheet("QWidget { background-color: #f5f5f5; }"); + + // Make fullscreen on Linux + showFullScreen(); + } +}; + +int main(int argc, char *argv[]) { + // Direct framebuffer rendering - no X11/Wayland server needed + // The Qt application interfaces directly with the Linux kernel framebuffer + qputenv("QT_QPA_PLATFORM", "linuxfb"); + + QApplication app(argc, argv); + + SparkOSMainWindow window; + window.show(); + + return app.exec(); +} + +#include "main.moc"