feat: Add SparkOS

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-21 17:08:35 +00:00
parent b6b534efca
commit 4a5c50ab76
48 changed files with 4073 additions and 0 deletions

49
sparkos/.dockerignore Normal file
View File

@@ -0,0 +1,49 @@
# Git
.git
.gitignore
.github
# Documentation
*.md
!README.md
ARCHITECTURE.md
CONTRIBUTING.md
LICENSE
# Build artifacts
init
*.o
*.a
*.so
*.img
*.iso
build/
# Generated rootfs contents (we build our own in Docker)
rootfs/bin/*
rootfs/sbin/init
rootfs/usr/
rootfs/lib/
rootfs/lib64/
rootfs/boot/
# Keep rootfs structure
!rootfs/etc/
!rootfs/root/
!rootfs/home/
# Temporary files
*.tmp
*.bak
/tmp/
# IDE and editor files
.vscode/
.idea/
*.swp
*.swo
*~
# OS files
.DS_Store
Thumbs.db

View File

@@ -0,0 +1,267 @@
name: Build and Release Disk Image
on:
push:
branches:
- main
- develop
tags:
- 'v*'
pull_request:
branches:
- main
- develop
workflow_dispatch:
jobs:
build-image:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build disk image using Docker
run: |
echo "Building SparkOS disk image..."
# Build the image builder container
docker buildx build \
--file Dockerfile.image \
--target image-builder \
--tag sparkos:image-builder \
--load \
.
# Create a container and extract the image
echo "Extracting disk image..."
CONTAINER_ID=$(docker create sparkos:image-builder)
docker cp "$CONTAINER_ID:/output/sparkos.img.gz" ./sparkos.img.gz
docker rm "$CONTAINER_ID"
echo "Disk image created successfully!"
ls -lh sparkos.img.gz
- name: Verify disk image
run: |
echo "Verifying UEFI-bootable disk image..."
if [ ! -f sparkos.img.gz ]; then
echo "ERROR: Disk image not found!"
exit 1
fi
# Show file info
ls -lh sparkos.img.gz
file sparkos.img.gz
# Decompress and check
echo "Decompressing to verify..."
gunzip -c sparkos.img.gz > sparkos.img
ls -lh sparkos.img
file sparkos.img
# Show partition table (should be GPT)
echo ""
echo "=== Partition Table (GPT) ==="
sudo fdisk -l sparkos.img || true
sudo parted sparkos.img print || true
# Try to mount and inspect partitions
echo ""
echo "=== Inspecting Partitions ==="
mkdir -p /tmp/sparkos_esp /tmp/sparkos_root
# Set up loop device
LOOP_DEV=$(sudo losetup -fP --show sparkos.img)
echo "Loop device: $LOOP_DEV"
ls -la ${LOOP_DEV}*
# Mount and check ESP
if sudo mount -o ro ${LOOP_DEV}p1 /tmp/sparkos_esp 2>/dev/null; then
echo "✓ EFI System Partition mounted"
echo "ESP contents:"
ls -laR /tmp/sparkos_esp/
if [ -f /tmp/sparkos_esp/EFI/BOOT/BOOTX64.EFI ]; then
echo "✓ UEFI bootloader (GRUB) found"
fi
if [ -f /tmp/sparkos_esp/boot/vmlinuz ]; then
echo "✓ Kernel found"
fi
sudo umount /tmp/sparkos_esp
fi
# Mount and check root partition
if sudo mount -o ro ${LOOP_DEV}p2 /tmp/sparkos_root 2>/dev/null; then
echo "✓ Root partition mounted"
echo "Root contents:"
ls -la /tmp/sparkos_root/
if [ -f /tmp/sparkos_root/sbin/init ]; then
echo "✓ Init binary found"
ls -lh /tmp/sparkos_root/sbin/init
fi
if [ -f /tmp/sparkos_root/bin/busybox ]; then
echo "✓ Busybox found"
fi
sudo umount /tmp/sparkos_root
fi
# Cleanup
sudo losetup -d $LOOP_DEV
echo ""
echo "=== Verification Complete ==="
echo "✓ UEFI-bootable image with GPT partition table"
echo "✓ EFI System Partition with GRUB"
echo "✓ Root partition with init system and busybox"
- name: Create release package
run: |
echo "Creating release package..."
mkdir -p release
# Move the compressed image
mv sparkos.img.gz release/
# Copy the README for the release
cp config/image-release-readme.txt release/README.txt
# Create a ZIP with the image and README
cd release || exit 1
zip sparkos-image.zip sparkos.img.gz README.txt
cd .. || exit 1
echo "Release package created!"
ls -lh release/
- name: Upload image artifact
uses: actions/upload-artifact@v4
with:
name: sparkos-image-${{ github.sha }}
path: release/sparkos-image.zip
retention-days: 90
- name: Create GitHub Release
if: startsWith(github.ref, 'refs/tags/')
uses: softprops/action-gh-release@v1
with:
files: release/sparkos-image.zip
body: |
# SparkOS UEFI-Bootable Disk Image Release ${{ github.ref_name }}
This release includes a **UEFI-bootable** disk image with SparkOS.
## What's Included
- **sparkos-image.zip**: Complete package with compressed disk image and README
## Features
✅ **UEFI Boot Support** - Boot on modern UEFI systems
✅ **GPT Partition Table** - Modern partitioning scheme
✅ **GRUB Bootloader** - Reliable UEFI bootloader
✅ **Linux Kernel** - Full kernel included
✅ **SparkOS Init System** - Custom init with busybox
✅ **Ready to Boot** - Write to USB and boot immediately
## Quick Start
### Write to USB and Boot
```bash
# Download and extract the package
wget https://github.com/johndoe6345789/SparkOS/releases/download/${{ github.ref_name }}/sparkos-image.zip
unzip sparkos-image.zip
# Decompress the image
gunzip sparkos.img.gz
# Write to USB drive (Linux - BE CAREFUL!)
sudo dd if=sparkos.img of=/dev/sdX bs=4M status=progress oflag=sync
```
**⚠️ WARNING**: Replace `/dev/sdX` with your actual USB device (e.g., `/dev/sdb`). This will **ERASE ALL DATA** on the target drive!
### Boot Instructions
1. Insert the USB drive into a UEFI-capable system
2. Enter BIOS/UEFI settings (usually F2, F12, DEL, or ESC at boot)
3. Select the USB drive as boot device
4. SparkOS will boot automatically after 3 seconds
### Inspect Partitions (Advanced)
```bash
# Set up loop device
LOOP_DEV=$(sudo losetup -fP --show sparkos.img)
# Mount ESP (EFI System Partition)
sudo mount ${LOOP_DEV}p1 /mnt
ls -la /mnt/EFI # View bootloader and kernel
sudo umount /mnt
# Mount root partition
sudo mount ${LOOP_DEV}p2 /mnt
ls -la /mnt # View SparkOS filesystem
sudo umount /mnt
# Cleanup
sudo losetup -d $LOOP_DEV
```
## Technical Details
- **Size**: ~1GB (compressed)
- **Partition Table**: GPT
- **ESP**: 200MB FAT32 (EFI System Partition)
- **Root**: ~800MB ext4
- **Bootloader**: GRUB (UEFI)
- **Kernel**: Linux kernel (from Ubuntu)
- **Init**: SparkOS custom init system
- **Shell**: Busybox
## Docker Image
A Docker image is also available:
```bash
docker pull ghcr.io/johndoe6345789/sparkos:${{ github.ref_name }}
```
## Documentation
See [README.md](https://github.com/johndoe6345789/SparkOS/blob/main/README.md) for full documentation.
## What's Changed
See commit history for detailed changes.
draft: false
prerelease: false
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Output summary
run: |
echo "### Disk Image Build Summary 💾" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Status:** ✅ Success" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Disk Image:**" >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
ls -lh release/sparkos.img.gz >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Release Package:**" >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
ls -lh release/sparkos-image.zip >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
if [[ "${{ github.ref }}" == refs/tags/* ]]; then
echo "**Release:** Created GitHub release for ${{ github.ref_name }}" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "Download from: https://github.com/${{ github.repository }}/releases/tag/${{ github.ref_name }}" >> $GITHUB_STEP_SUMMARY
else
echo "**Artifact:** Uploaded as workflow artifact (available for 90 days)" >> $GITHUB_STEP_SUMMARY
fi

View File

@@ -0,0 +1,115 @@
name: Docker Build and Publish
on:
push:
branches:
- main
- develop
tags:
- 'v*'
pull_request:
branches:
- main
- develop
workflow_dispatch:
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
build-and-test:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to GitHub Container Registry
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
type=sha
type=raw,value=latest,enable={{is_default_branch}}
- name: Build Docker image
uses: docker/build-push-action@v5
with:
context: .
file: ./Dockerfile
platforms: ${{ github.event_name == 'pull_request' && 'linux/amd64' || 'linux/amd64,linux/arm64' }}
push: ${{ github.event_name != 'pull_request' }}
load: ${{ github.event_name == 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Test Docker image
run: |
set -e # Exit immediately if a command exits with a non-zero status
echo "Testing SparkOS Docker image..."
# Get the first tag from the metadata output
IMAGE_TAG=$(echo "${{ steps.meta.outputs.tags }}" | head -n1)
echo "Using image: $IMAGE_TAG"
# For PRs, image is loaded locally; for branches, pull from GHCR
if [ "${{ github.event_name }}" != "pull_request" ]; then
echo "Pulling image from GHCR for testing..."
docker pull "$IMAGE_TAG"
fi
# Run the container and check output
echo "Running container entrypoint test..."
if ! docker run --rm "$IMAGE_TAG"; then
echo "ERROR: Container entrypoint test failed!"
exit 1
fi
# Verify init binary exists and is executable
echo "Verifying init binary is executable..."
if ! docker run --rm "$IMAGE_TAG" sh -c "test -x /sparkos/rootfs/sbin/init && echo 'Init binary is executable'"; then
echo "ERROR: Init binary verification failed!"
exit 1
fi
echo "Docker image test completed successfully!"
- name: Output image details
if: github.event_name != 'pull_request'
run: |
echo "### Docker Image Published! 🐳" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Registry:** ${{ env.REGISTRY }}" >> $GITHUB_STEP_SUMMARY
echo "**Repository:** ${{ env.IMAGE_NAME }}" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Tags:**" >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
echo "${{ steps.meta.outputs.tags }}" >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Pull command:**" >> $GITHUB_STEP_SUMMARY
echo '```bash' >> $GITHUB_STEP_SUMMARY
echo "docker pull ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest" >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY

169
sparkos/.github/workflows/release.yml vendored Normal file
View File

@@ -0,0 +1,169 @@
name: Build and Release
on:
push:
branches:
- main
- develop
tags:
- 'v*'
pull_request:
branches:
- main
- develop
workflow_dispatch:
jobs:
build-release:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up build environment
run: |
sudo apt-get update
sudo apt-get install -y gcc make
- name: Build init binary
run: |
echo "Building SparkOS init system..."
make init
echo "Build complete!"
- name: Verify build
run: |
echo "Verifying init binary..."
if [ ! -f init ]; then
echo "ERROR: init binary not found!"
exit 1
fi
ls -lh init
file init
ldd init 2>&1 || echo "Static binary (no dependencies)"
echo "Verification complete!"
- name: Prepare release package
run: |
echo "Preparing release package..."
mkdir -p release/sparkos
# Copy compiled binary
cp init release/sparkos/
# Copy essential files
cp README.md release/sparkos/
cp LICENSE release/sparkos/
cp ARCHITECTURE.md release/sparkos/
cp CONTRIBUTING.md release/sparkos/
cp Makefile release/sparkos/
# Copy source for reference
cp -r src release/sparkos/
# Copy scripts
cp -r scripts release/sparkos/
# Copy config
cp -r config release/sparkos/
# Copy rootfs structure (without generated content)
mkdir -p release/sparkos/rootfs
# Copy rootfs directories if they exist (some may not be populated)
for dir in etc root home; do
if [ -d "rootfs/$dir" ]; then
cp -r "rootfs/$dir" release/sparkos/rootfs/
else
echo "Note: rootfs/$dir does not exist, skipping"
fi
done
# Copy README for the release
cp config/RELEASE_README.md release/sparkos/RELEASE_README.md
echo "Package prepared in release/sparkos/"
ls -la release/sparkos/
- name: Create release archive
run: |
echo "Creating release archive..."
cd release
zip -r ../sparkos-release.zip sparkos/
cd ..
echo "Archive created!"
ls -lh sparkos-release.zip
unzip -l sparkos-release.zip | head -30
- name: Upload release artifact
uses: actions/upload-artifact@v4
with:
name: sparkos-release-${{ github.sha }}
path: sparkos-release.zip
retention-days: 90
- name: Create GitHub Release
if: startsWith(github.ref, 'refs/tags/')
uses: softprops/action-gh-release@v1
with:
files: sparkos-release.zip
body: |
# SparkOS Release ${{ github.ref_name }}
This release includes:
- Pre-compiled init binary (statically linked)
- Complete source code
- Build scripts and configuration
- Root filesystem structure
- Documentation
## Quick Start
1. Download `sparkos-release.zip`
2. Extract the archive
3. Use the pre-built `init` binary or rebuild from source
4. Follow README.md for complete setup instructions
## Docker Image
A Docker image is also available:
```bash
docker pull ghcr.io/johndoe6345789/sparkos:${{ github.ref_name }}
```
## What's Changed
See commit history for detailed changes.
draft: false
prerelease: false
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Output summary
run: |
echo "### Build and Release Summary 📦" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Status:** ✅ Success" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Init Binary:**" >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
ls -lh init >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Release Archive:**" >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
ls -lh sparkos-release.zip >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
if [[ "${{ github.ref }}" == refs/tags/* ]]; then
echo "**Release:** Created GitHub release for ${{ github.ref_name }}" >> $GITHUB_STEP_SUMMARY
else
echo "**Artifact:** Uploaded as workflow artifact (available for 90 days)" >> $GITHUB_STEP_SUMMARY
fi
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Archive Contents (preview):**" >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
unzip -l sparkos-release.zip | head -30 >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY

74
sparkos/.gitignore vendored Normal file
View File

@@ -0,0 +1,74 @@
# Prerequisites
*.d
# Compiled Object files
*.slo
*.lo
*.o
*.obj
# Precompiled Headers
*.gch
*.pch
# Linker files
*.ilk
# Debugger Files
*.pdb
# Compiled Dynamic libraries
*.so
*.dylib
*.dll
# Fortran module files
*.mod
*.smod
# Compiled Static libraries
*.lai
*.la
*.a
*.lib
# Executables
*.exe
*.out
*.app
# debug information files
*.dwo
# Build artifacts
build/
init
*.img
*.iso
*.zip
release/
# Temporary files
/tmp/
*.tmp
*.bak
# Root filesystem (generated)
rootfs/bin/*
rootfs/sbin/*
rootfs/usr/bin/*
rootfs/usr/sbin/*
rootfs/usr/lib/*
rootfs/usr/lib64/*
rootfs/lib/*
rootfs/lib64/*
rootfs/boot/*
# Keep structure but ignore contents
!rootfs/README.txt
!rootfs/etc/
!rootfs/root/
!rootfs/home/
# CodeQL
_codeql_detected_source_root

153
sparkos/ARCHITECTURE.md Normal file
View File

@@ -0,0 +1,153 @@
# SparkOS Architecture
## Overview
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.
## Core Philosophy
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
## System Architecture
```
Boot Sequence:
Hardware → UEFI/BIOS → GRUB → Linux Kernel → init (PID 1) → Qt6 GUI
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 Ditch Unix Conventions?
Traditional Unix systems were designed for multi-user, time-sharing mainframes in the 1970s. Modern personal computing and embedded systems have different needs:
- **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
### Why Keep Linux Kernel?
- **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
### Why Qt6 GUI?
- **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
### Why No X11/Wayland?
- **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
### 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
### Planned Components
1. **Qt6/QML GUI**
- Full-screen application
- Android-like interface design
- Desktop-oriented workflow
2. **Wayland Compositor**
- Custom compositor for SparkOS
- Minimal resource usage
- Touch and mouse support
3. **Network Management**
- Qt6 NetworkManager integration
- WiFi configuration UI
- VPN and advanced networking UI
## Security Considerations
- Static binaries reduce attack surface
- Minimal running processes
- Root filesystem can be read-only
- Sudo for privilege escalation
- Future: SELinux/AppArmor integration
## Performance
- Fast boot time (seconds, not minutes)
- Low memory footprint (~20MB base init system)
- No unnecessary background services
- Efficient init system (no external dependencies)
## Portability
- AMD64 (x86_64) and ARM64 (aarch64) architectures
- dd-able disk images
- USB flash drive ready
- Multi-architecture Docker images
## Extension Points
The architecture is designed for easy extension:
1. **Init system**: Can be enhanced with service management
2. **Filesystem**: Can add more mount points and partitions
3. **Boot process**: Can integrate other bootloaders
4. **GUI**: Clean separation allows GUI to be optional
## Development Workflow
1. Modify source code in `src/`
2. Build with `make init`
3. Test init in isolation
4. Install to `rootfs/` with `make install`
5. Create test image with `sudo make image`
6. Test on real hardware or VM
## References
- Linux Kernel Documentation
- Filesystem Hierarchy Standard (FHS)
- POSIX Standards
- Qt6 Documentation
- Wayland Protocol Specification

76
sparkos/CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,76 @@
# Contributing to SparkOS
Thank you for your interest in contributing to SparkOS!
## Project Goals
SparkOS aims to be:
- **Minimal**: Only essential components
- **Clean**: Well-documented, readable code
- **Portable**: dd-able to USB drives
- **Extensible**: Easy to add features incrementally
## Development Setup
1. Clone the repository:
```bash
git clone https://github.com/johndoe6345789/SparkOS.git
cd SparkOS
```
2. Build the system:
```bash
./scripts/build.sh
```
3. Make your changes
4. Test your changes:
```bash
make clean
make all
```
## Code Style
- **C/C++ Code**: Follow Linux kernel style guidelines
- Use tabs for indentation
- Keep lines under 80 characters when reasonable
- Comment complex logic
- **Shell Scripts**: Follow Google Shell Style Guide
- For runtime scripts (inside rootfs): Use `#!/bin/sh` for POSIX-compliant scripts (busybox compatibility)
- For build scripts (host system): Can use `#!/bin/bash` when bash-specific features are needed
- Quote variables
- Use meaningful variable names
- **Documentation**: Write clear, concise documentation
- Update README when adding features
- Comment non-obvious code
- Include usage examples
## Submitting Changes
1. Fork the repository
2. Create a feature branch (`git checkout -b feature/my-feature`)
3. Make your changes
4. Test thoroughly
5. Commit with descriptive messages
6. Push to your fork
7. Open a Pull Request
## What to Contribute
Priority areas:
- Bug fixes
- Documentation improvements
- Build system enhancements
- Testing infrastructure
- Qt6/QML GUI components
- Wayland integration
- Package management
- Network configuration
## Questions?
Open an issue on GitHub for questions or discussions.

48
sparkos/Dockerfile Normal file
View File

@@ -0,0 +1,48 @@
# SparkOS Docker Image
# Multi-stage build for minimal final image size
# Build stage - use gcc image which has all build tools pre-installed
FROM gcc:13-bookworm AS builder
# Set working directory
WORKDIR /build
# Copy source files
COPY src/ ./src/
COPY Makefile .
COPY scripts/ ./scripts/
# Build the init system
RUN make init
# Runtime stage - use Alpine for minimal size
FROM alpine:3.19
# Install file command for testing init binary
# file package provides the file(1) command to determine file type
COPY scripts/docker-install-packages.sh /tmp/
RUN /tmp/docker-install-packages.sh
# SparkOS Philosophy: No CLI tools, GUI-only experience
# The init system is completely self-contained with no external dependencies
# All functionality is provided through direct system calls in C
# Create minimal rootfs structure
COPY scripts/docker-setup-rootfs.sh /tmp/
RUN /tmp/docker-setup-rootfs.sh
# Copy built init binary from builder
COPY --from=builder /build/init /sparkos/rootfs/sbin/init
# Set up basic configuration files
COPY scripts/docker-setup-config.sh /tmp/
RUN /tmp/docker-setup-config.sh
# Create a test entrypoint
COPY scripts/test.sh /sparkos/test.sh
RUN chmod +x /sparkos/test.sh
WORKDIR /sparkos
# Set entrypoint
ENTRYPOINT ["/sparkos/test.sh"]

36
sparkos/Dockerfile.image Normal file
View File

@@ -0,0 +1,36 @@
# Dockerfile for building UEFI-bootable SparkOS image
# Creates a .img file with GPT partition table, ESP, and GRUB
FROM ubuntu:22.04 AS image-builder
# Install required tools (includes Qt6 and CMake)
COPY scripts/docker-image-install-tools.sh /tmp/
RUN /tmp/docker-image-install-tools.sh
WORKDIR /build
# Copy source files
COPY src/ ./src/
COPY Makefile .
COPY scripts/ ./scripts/
COPY config/ ./config/
COPY rootfs/ ./rootfs/
# Build the init binary and Qt6 GUI application
RUN make init
RUN make gui
# Install to rootfs
RUN make install
# Download a minimal Linux kernel (using Ubuntu's kernel for now)
COPY scripts/docker-image-download-kernel.sh /tmp/
RUN /tmp/docker-image-download-kernel.sh
# Create UEFI-bootable image with GPT partition table
COPY scripts/docker-image-create-uefi.sh /tmp/
RUN /tmp/docker-image-create-uefi.sh
# Final stage - export the image
FROM scratch AS export
COPY --from=image-builder /output/sparkos.img.gz /sparkos.img.gz

View File

@@ -0,0 +1,111 @@
# SparkOS Init System Verification
This document demonstrates SparkOS's self-contained init system with no external dependencies.
## Docker Container Verification
When you run the SparkOS Docker container, it automatically verifies the init system:
```bash
docker run --rm ghcr.io/johndoe6345789/sparkos:latest
```
## Expected Output
The container startup will display comprehensive init system verification:
```
SparkOS Docker Test Environment
================================
Verifying SparkOS init binary...
--------------------------------
✓ Init binary exists
-rwxr-xr-x 1 root root 20.0K Jan 2 00:00 /sparkos/rootfs/sbin/init
File type:
/sparkos/rootfs/sbin/init: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked
Dependencies:
Static binary (no dependencies)
Root filesystem structure:
--------------------------
total 16
drwxr-xr-x 5 root root 4096 Jan 2 00:00 .
drwxr-xr-x 1 root root 4096 Jan 2 00:00 ..
drwxr-xr-x 2 root root 4096 Jan 2 00:00 etc
drwxr-xr-x 2 root root 4096 Jan 2 00:00 sbin
drwxr-xr-x 2 root root 4096 Jan 2 00:00 usr
================================
✓ SparkOS is ready for testing!
================================
Summary:
- Init: Custom SparkOS init system (no external dependencies)
- Architecture: GUI-only, no CLI/shell
- Network: Direct C implementation via ioctl
- Philosophy: Pure GUI experience, network-first
Note: SparkOS has no CLI tools (no busybox, no shell)
All functionality is provided through the Qt6 GUI
To test the init system:
docker run --rm <image> /sparkos/rootfs/sbin/init
```
## What This Proves
The verification output demonstrates:
1. **Self-contained init**: Statically linked binary with no external dependencies
2. **No CLI tools**: No busybox, no shell, no Unix utilities
3. **Minimal footprint**: Only essential files in root filesystem
4. **Pure C implementation**: All functionality (mounting, networking) via system calls
## Key Init Features
- **Filesystem mounting**: Direct mount() system calls (no mount binary)
- **Network initialization**: Direct ioctl calls (no ip/ifconfig/udhcpc)
- **Process management**: Built-in SIGCHLD handler for zombie reaping
- **GUI spawning**: Direct execve() of Qt6 GUI application
- **Overlay filesystem**: Immutable base with writable /var overlay
## SparkOS Philosophy
SparkOS eliminates traditional Unix layers:
- **No busybox**: All functionality in init or Qt6 GUI
- **No shell**: Direct kernel-to-GUI communication
- **No CLI tools**: Everything through GUI interface
- **No users/authentication**: Single-user, direct boot to GUI
- **Network-first**: Networking integrated into GUI, not CLI
## Init System Architecture
```
Init Process (PID 1)
├── Mount filesystems (proc, sys, dev, tmp)
├── Setup overlay filesystem (/var)
├── Initialize network interfaces (ioctl)
└── Spawn Qt6 GUI → Respawn on exit
```
All operations use direct system calls:
- `mount()` for filesystem mounting
- `mkdir()` for directory creation
- `socket()` + `ioctl()` for network initialization
- `fork()` + `execve()` for GUI spawning
- `waitpid()` for process reaping
## Verification in Code
The verification is performed by `/sparkos/test.sh` which:
1. Checks if init binary exists and is executable
2. Verifies it's statically linked (no dependencies)
3. Shows root filesystem structure
4. Confirms the GUI-only architecture
This ensures that anyone running the SparkOS Docker container can immediately see proof that SparkOS uses a completely self-contained init system with no external dependencies.

21
sparkos/LICENSE Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2025 johndoe6345789
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

77
sparkos/Makefile Normal file
View File

@@ -0,0 +1,77 @@
# SparkOS Makefile
# Builds the minimal Linux distribution
CC = gcc
CFLAGS = -Wall -O2 -static
DESTDIR = rootfs
IMAGE = sparkos.img
IMAGE_SIZE = 512M
.PHONY: all clean init gui image image-docker help install docker-release
all: init gui
help:
@echo "SparkOS Build System"
@echo "===================="
@echo "Targets:"
@echo " make init - Build the init system"
@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)"
@echo " make clean - Clean build artifacts"
@echo ""
@echo "Note: Creating a bootable image requires root privileges"
@echo " and various tools (debootstrap, syslinux, etc.)"
@echo ""
@echo "For easier image building, use Docker:"
@echo " make image-docker"
@echo " OR: ./scripts/build-image.sh"
init: src/init.c
@echo "Building SparkOS init system..."
$(CC) $(CFLAGS) -o init src/init.c
@echo "Init system built successfully: ./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..."
@if [ "$$(id -u)" -ne 0 ]; then \
echo "ERROR: Image creation requires root privileges"; \
echo "Run: sudo make image"; \
exit 1; \
fi
@./scripts/create_image.sh
image-docker:
@echo "Building bootable image using Docker..."
@./scripts/build-image.sh
docker-release:
@echo "Building release package using Docker..."
@./scripts/docker-release.sh
clean:
@echo "Cleaning build artifacts..."
rm -f init
rm -f $(IMAGE)
rm -rf build/
rm -rf release/
@echo "Clean complete"

482
sparkos/README.md Normal file
View File

@@ -0,0 +1,482 @@
# SparkOS
A revolutionary operating system that ditches Unix conventions for a modern, network-first approach. SparkOS features:
- **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 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
The current MVP provides:
- ✅ Custom init system written in C (no external dependencies)
- ✅ GUI-only architecture (no CLI/shell)
- ✅ dd-able AMD64 image creation scripts
- ✅ Minimal root filesystem structure
- ✅ Build system (Makefile)
- ✅ Direct network initialization via C ioctl
- ✅ DNS configuration with public fallback servers
- ✅ Docker container for testing
- ✅ Automated builds and publishing to GHCR
- ✅ Multi-architecture Docker images (AMD64 and ARM64)
- ✅ CI/CD pipeline for compiled release packages
- ✅ GitHub releases with pre-built binaries
## Prerequisites
To build SparkOS, you need:
- GCC compiler
- GNU Make
- Linux system (for building)
To create bootable images (optional):
- Root privileges
- `syslinux` bootloader
- `parted` partitioning tool
- `losetup` for loop devices
- `mkfs.ext4` filesystem tools
## Quick Start
### Using UEFI-Bootable Disk Image (Recommended - Boot from USB)
Download the UEFI-bootable image from the [GitHub Releases page](https://github.com/johndoe6345789/SparkOS/releases):
```bash
# Download the disk image (replace VERSION with actual version, e.g., v1.0.0)
wget https://github.com/johndoe6345789/SparkOS/releases/download/VERSION/sparkos.img.gz
# Decompress the image
gunzip sparkos.img.gz
# Write to USB drive (Linux - BE CAREFUL!)
sudo dd if=sparkos.img of=/dev/sdX bs=4M status=progress oflag=sync
```
**⚠️ WARNING**: Replace `/dev/sdX` with your actual USB device (e.g., `/dev/sdb`). This will **DESTROY ALL DATA** on the target drive!
**Boot Instructions:**
1. Insert the USB drive into a UEFI-capable system
2. Enter BIOS/UEFI settings (usually F2, F12, DEL, or ESC at boot)
3. Select the USB drive as boot device
4. SparkOS will boot automatically
The UEFI-bootable disk image includes:
-**UEFI boot support** with GRUB bootloader
-**GPT partition table** with ESP (EFI System Partition)
-**Linux kernel** ready to boot
-**SparkOS init system** (completely self-contained, no external dependencies)
-**Ready to boot** - Direct to Qt6 GUI, no CLI
### Using Pre-built Binary Package
Download the binary package from the [GitHub Releases page](https://github.com/johndoe6345789/SparkOS/releases):
```bash
# Download the latest release (replace VERSION with actual version, e.g., v1.0.0)
wget https://github.com/johndoe6345789/SparkOS/releases/download/VERSION/sparkos-release.zip
# Extract the package
unzip sparkos-release.zip
cd sparkos/
# The init binary is already compiled and ready to use
ls -lh init
# Copy to your rootfs or use directly
cp init /path/to/your/rootfs/sbin/init
```
The release package includes:
- Pre-compiled init binary (statically linked, ready to use)
- Complete source code
- Build scripts and configuration
- Root filesystem structure
- Full documentation
### Using Docker (Recommended for Testing)
The easiest way to test SparkOS is using the pre-built Docker image from GitHub Container Registry:
```bash
# Pull and run the latest image (automatically selects the correct architecture)
docker pull ghcr.io/johndoe6345789/sparkos:latest
docker run --rm ghcr.io/johndoe6345789/sparkos:latest
# Or build locally
docker build -t sparkos:local .
docker run --rm sparkos:local
# Or use Docker Compose for even simpler testing
docker-compose up
# Build for specific architecture
docker buildx build --platform linux/amd64 -t sparkos:amd64 --load .
docker buildx build --platform linux/arm64 -t sparkos:arm64 --load .
```
The Docker image includes:
- Pre-built init system binary
- Minimal root filesystem structure
- Test environment for validation
- **No CLI tools**: Pure GUI-only architecture
- **Multi-architecture support**: Available for both AMD64 (x86_64) and ARM64 (aarch64) architectures
When you run the Docker image, it automatically verifies:
- Custom init system binary (statically linked, no dependencies)
- Root filesystem structure
Images are automatically built and published to [GitHub Container Registry](https://github.com/johndoe6345789/SparkOS/pkgs/container/sparkos) on every push to main branch.
**Building Releases with Docker (No Root Required):**
Create release packages easily using Docker without needing root privileges or special tools:
```bash
# Build a release package for version v1.0.0
./scripts/docker-release.sh v1.0.0
# The release ZIP will be created in release/sparkos-release.zip
# This is the same artifact that GitHub Actions creates
```
### Building the Init System
```bash
# Build the init binary
make init
# Or use the quick build script
./scripts/build.sh
```
### Setting Up Root Filesystem
```bash
# Create the root filesystem structure
./scripts/setup_rootfs.sh
# Install init to rootfs
make install
```
### Creating a UEFI-Bootable Image
**Using Docker (Recommended - No Root Required):**
Build UEFI-bootable disk images easily using Docker without needing root privileges on your host:
```bash
# Build the UEFI-bootable disk image using Docker
make image-docker
# Or use the script directly
./scripts/build-image.sh
# The compressed UEFI-bootable image will be in release/sparkos.img.gz
```
This creates a complete UEFI-bootable image with:
- GPT partition table
- EFI System Partition (ESP) with FAT32
- GRUB UEFI bootloader
- Linux kernel
- SparkOS init system (no external dependencies)
**Traditional Method (Requires Root):**
⚠️ **Warning**: This method is for creating custom partitioned images and requires root privileges.
```bash
# Install required tools (Ubuntu/Debian)
sudo apt-get install syslinux parted
# Build everything and create image
make all
sudo make image
```
### Installing to USB Drive
Once you have created the `sparkos.img` file, use the installation script to write it to a USB drive or storage device:
```bash
# Use the installation script (RECOMMENDED)
sudo ./scripts/install.sh /dev/sdX
# The script will:
# - Validate the target drive
# - Display warnings about data destruction
# - Require confirmation before proceeding
# - Show progress during installation
# - Verify successful installation
```
Replace `/dev/sdX` with your actual USB device (e.g., `/dev/sdb`, `/dev/nvme1n1`).
**⚠️ WARNING**: This will permanently erase all data on the target drive!
## Project Structure
```
SparkOS/
├── .github/ # GitHub Actions workflows
│ └── workflows/
│ └── docker-publish.yml # Docker build and publish workflow
├── config/ # Build configuration files
│ └── build.conf # Build parameters
├── scripts/ # Build and setup scripts
│ ├── build.sh # Quick build script
│ ├── setup_rootfs.sh # Root filesystem setup
│ ├── create_image.sh # Image creation script
│ └── install.sh # Installation script for USB drives
├── src/ # Source code
│ └── init.c # Custom init system
├── rootfs/ # Root filesystem (generated)
│ ├── bin/ # Essential binaries
│ ├── sbin/ # System binaries
│ ├── etc/ # Configuration files
│ └── ... # Standard FHS directories
├── Dockerfile # Docker image definition
├── Makefile # Build system
└── README.md # This file
```
## Architecture
### Init System
SparkOS uses a custom init system (`/sbin/init`) that:
- Mounts essential filesystems (proc, sys, dev, tmp) via direct system calls
- Initializes network interfaces via direct C ioctl calls
- Spawns Qt6 GUI application directly
- Handles process reaping
- Respawns GUI on exit
- **No external dependencies**: Completely self-contained
### Root Filesystem
Minimal filesystem structure for GUI-only OS:
- `/sbin`: Init binary only
- `/etc`: Minimal system configuration
- `/proc`, `/sys`, `/dev`: Kernel interfaces
- `/tmp`: Temporary files
- `/usr`: Qt6 GUI application and libraries
- `/var`: Variable data (overlay mount)
- `/root`: Root home
### Networking
SparkOS provides network initialization through direct C code:
- **Interface Management**: Direct ioctl calls to bring up network interfaces
- **DNS**: Fallback to public DNS servers (8.8.8.8, 8.8.4.4, 1.1.1.1, 1.0.0.1)
- **DHCP**: Managed by Qt6 NetworkManager in GUI
- **WiFi**: Configured through Qt6 GUI
## Development
### CI/CD and Docker
SparkOS uses GitHub Actions for continuous integration and delivery:
**Automated Builds:**
- Docker images are automatically built on every push to main/develop branches
- Compiled release packages are automatically built on every push to main/develop branches
- Both are also built for pull requests (testing only, not published)
- Tagged releases automatically create versioned Docker images and GitHub releases with compiled binaries
- **Multi-architecture builds**: Images are built for both AMD64 (x86_64) and ARM64 (aarch64)
**Compiled Releases:**
- Pre-compiled init binaries are available as GitHub releases for version tags
- Release packages include: compiled init binary, source code, build scripts, and documentation
- Download releases from the [GitHub Releases page](https://github.com/johndoe6345789/SparkOS/releases)
- Build artifacts are available for all workflow runs (retained for 90 days)
**Container Registry:**
- Images are published to GitHub Container Registry (GHCR)
- Pull images: `docker pull ghcr.io/johndoe6345789/sparkos:latest`
- Available tags: `latest`, `main`, `develop`, version tags (e.g., `v1.0.0`)
- Docker will automatically select the correct architecture for your platform
**Docker Development:**
```bash
# Build Docker image locally
docker build -t sparkos:dev .
# Build for multiple architectures (requires Docker Buildx)
docker buildx build --platform linux/amd64,linux/arm64 -t sparkos:multiarch .
# Test the image
docker run --rm sparkos:dev
# Or use Docker Compose
docker-compose up
# Inspect the init binary
docker run --rm sparkos:dev sh -c "ls -lh /sparkos/rootfs/sbin/init"
```
### Creating Releases
**Using Docker (Recommended - No Root Required):**
Build release packages locally using Docker without needing root privileges:
```bash
# Build a release package
./scripts/docker-release.sh v1.0.0
# The release ZIP will be in release/sparkos-release.zip
# This is identical to what GitHub Actions creates
```
**Creating a GitHub Release:**
1. **Commit and push your changes** to the main branch
2. **Create and push a version tag:**
```bash
git tag v1.0.0
git push origin v1.0.0
```
3. **GitHub Actions will automatically:**
- Build the init binary
- Create the release package ZIP
- Build and publish Docker images (AMD64 + ARM64)
- Create a GitHub Release with the artifacts
- Publish to GitHub Container Registry
The release will be available at:
- **GitHub Releases:** https://github.com/johndoe6345789/SparkOS/releases
- **Docker Images:** `ghcr.io/johndoe6345789/sparkos:v1.0.0`
**Manual Release Creation:**
You can also create a release manually:
1. Go to https://github.com/johndoe6345789/SparkOS/releases/new
2. Choose or create a tag (e.g., `v1.0.0`)
3. Fill in the release title and description
4. Upload the `sparkos-release.zip` (built locally with `docker-release.sh`)
5. Publish the release
For detailed instructions on creating releases, see [RELEASING.md](RELEASING.md).
### Building Components
```bash
# Build init system only
make init
# Build release package using Docker
make docker-release
# Install to rootfs
make install
# Clean build artifacts
make clean
# Show help
make help
```
### Adding Components to Root Filesystem
To create a fully functional bootable system:
```bash
# Required components:
# 1. Qt6 GUI application - Build with make gui
# 2. Qt6 libraries - Copy Qt6 runtime libraries to rootfs/usr/lib
# 3. Linux kernel - Include kernel binary for bootloader
# Qt6 GUI is built and installed via:
make gui
make install # Installs to rootfs/usr/bin/sparkos-gui
# Note: Qt6 must be compiled with linuxfb support for framebuffer rendering
```
## Future Roadmap
- [ ] Qt6/QML full screen GUI implementation
- [ ] Wayland compositor integration
- [ ] Network management via Qt6 NetworkManager
- [ ] WiFi configuration through GUI
- [ ] Advanced network configuration UI
- [ ] System settings and configuration UI
## Contributing
Contributions are welcome! This is an early-stage project focused on:
1. Maintaining minimal footprint
2. Clean, readable code
3. Proper documentation
4. GUI-only architecture (no CLI/shell)
## License
See LICENSE file for details.
## Notes
This is an MVP implementation. The system currently provides:
- Custom init system with direct network initialization
- GUI-only architecture (no CLI/shell)
- Build infrastructure
- Image creation tooling
- Self-contained init with no external dependencies
To create a fully bootable system, you'll also need:
- Linux kernel binary (`vmlinuz`) with framebuffer and networking support
- Qt6 GUI application (sparkos-gui)
- Qt6 runtime libraries
- Bootloader installation (handled by scripts)
Minimum System Requirements:
- Kernel: Linux kernel with framebuffer and networking support
- Init: Custom SparkOS init (included, no dependencies)
- GUI: Qt6 application with linuxfb platform support
- Libraries: Qt6 runtime libraries for GUI
System Philosophy:
- **No CLI tools**: Everything through Qt6 GUI
- **No shell**: Direct kernel-to-GUI communication
- **No busybox**: Self-contained init system
- **Network-first**: Networking integrated into GUI

233
sparkos/RELEASING.md Normal file
View File

@@ -0,0 +1,233 @@
# SparkOS Release Guide
This guide explains how to create and publish releases for SparkOS.
## Release Methods
SparkOS supports two ways to create releases:
1. **Automatic (Recommended)**: Push a version tag to trigger GitHub Actions
2. **Manual**: Build locally and upload to GitHub
## Method 1: Automatic Release (Recommended)
This method uses GitHub Actions to automatically build and publish releases.
### Prerequisites
- Push access to the repository
- All changes committed and pushed to `main` branch
### Steps
1. **Ensure everything is ready**
```bash
# Make sure you're on main and up to date
git checkout main
git pull origin main
# Verify the build works
make init
```
2. **Create and push a version tag**
```bash
# Create a tag (use semantic versioning: v1.0.0, v2.1.3, etc.)
git tag v1.0.0
# Push the tag to GitHub
git push origin v1.0.0
```
3. **Wait for GitHub Actions**
- Go to https://github.com/johndoe6345789/SparkOS/actions
- Two workflows will run:
- **"Build and Release"**: Creates the release ZIP
- **"Docker Build and Publish"**: Publishes Docker images
- Both should complete successfully (green checkmarks)
4. **Verify the release**
- Go to https://github.com/johndoe6345789/SparkOS/releases
- Your new release should appear with `sparkos-release.zip` attached
- Docker images are available at `ghcr.io/johndoe6345789/sparkos:v1.0.0`
### What Gets Published
When you push a version tag, GitHub Actions automatically:
- ✅ Builds the init binary (statically linked)
- ✅ Creates a release package ZIP containing:
- Compiled init binary
- Complete source code
- Build scripts and configuration
- Root filesystem structure
- Full documentation
- ✅ Creates a GitHub Release at `/releases`
- ✅ Builds multi-architecture Docker images (AMD64 + ARM64)
- ✅ Publishes Docker images to GitHub Container Registry
- ✅ Tags Docker images with version number
## Method 2: Manual Release
Use this method if you need to build releases locally without pushing tags.
### Prerequisites
- Docker installed locally
- `zip` utility installed
### Steps
1. **Build the release package using Docker**
```bash
# Build for a specific version
./scripts/docker-release.sh v1.0.0
# Or use Make
make docker-release
# The package will be created at: release/sparkos-release.zip
```
2. **Verify the package**
```bash
# Check the file was created
ls -lh release/sparkos-release.zip
# List contents
unzip -l release/sparkos-release.zip | head -40
```
3. **Create a GitHub Release manually**
- Go to https://github.com/johndoe6345789/SparkOS/releases/new
- Fill in:
- **Tag**: Create a new tag (e.g., `v1.0.0`)
- **Title**: `SparkOS v1.0.0` (or similar)
- **Description**: List changes and features
- **Upload** the `sparkos-release.zip` file
- Click **"Publish release"**
### What's Included
The Docker-based release script creates the exact same package as GitHub Actions:
- Compiled init binary (statically linked, ready to use)
- Complete source code
- Build scripts (including `docker-release.sh`)
- Configuration files
- Root filesystem structure
- Full documentation (README, ARCHITECTURE, CONTRIBUTING)
## Testing Before Release
Always test your changes before creating a release:
### Test the Build
```bash
# Test compilation
make clean && make init
# Verify the binary
file init
ldd init # Should show "not a dynamic executable" (static)
```
### Test with Docker
```bash
# Build the Docker image
docker build -t sparkos:test .
# Run the test environment
docker run --rm sparkos:test
# Or use Docker Compose
docker-compose up
```
### Test the Release Script
```bash
# Build a test release package
./scripts/docker-release.sh test
# Verify it was created
ls -lh release/sparkos-release.zip
```
## Release Checklist
Before creating a release:
- [ ] All changes are committed and pushed to `main`
- [ ] Build succeeds: `make init` works
- [ ] Docker build succeeds: `docker build -t sparkos:test .` works
- [ ] Documentation is up to date (README, ARCHITECTURE, etc.)
- [ ] Version follows semantic versioning (vMAJOR.MINOR.PATCH)
- [ ] CHANGELOG or release notes are prepared (if applicable)
## Troubleshooting
### GitHub Actions Fails
1. Check the workflow logs at https://github.com/johndoe6345789/SparkOS/actions
2. Common issues:
- Build errors: Check if `make init` works locally
- Permission errors: Ensure `contents: write` permission in workflow
- Docker errors: Verify Dockerfile builds locally
### Release Not Created
- Ensure you pushed a tag starting with `v` (e.g., `v1.0.0`)
- Check that the workflow has `contents: write` permissions
- Verify the workflow completed successfully (green checkmark)
### Docker Images Not Published
- Check the "Docker Build and Publish" workflow logs
- Ensure the tag was pushed (not just created locally)
- Verify `packages: write` permission in workflow
## Version Numbering
Use semantic versioning for releases:
- **v1.0.0**: First stable release
- **v1.1.0**: New features, backward compatible
- **v1.1.1**: Bug fixes only
- **v2.0.0**: Breaking changes
## Release Artifacts
Each release includes:
1. **GitHub Release Page**
- Release notes
- Downloadable `sparkos-release.zip`
- Link to Docker images
2. **Docker Images** (automatically published)
- `ghcr.io/johndoe6345789/sparkos:v1.0.0` (specific version)
- `ghcr.io/johndoe6345789/sparkos:1.0` (minor version)
- `ghcr.io/johndoe6345789/sparkos:1` (major version)
- `ghcr.io/johndoe6345789/sparkos:latest` (if released from main)
3. **Multi-Architecture Support**
- Linux AMD64 (x86_64)
- Linux ARM64 (aarch64)
## Next Steps
After releasing:
1. Announce the release (if applicable)
2. Update documentation links to point to the new version
3. Test the release on different platforms
4. Monitor for issues and prepare patches if needed
## Support
For questions or issues with releases:
- Open an issue: https://github.com/johndoe6345789/SparkOS/issues
- Check workflow logs: https://github.com/johndoe6345789/SparkOS/actions

View File

@@ -0,0 +1,59 @@
# SparkOS Release Package
This package contains the compiled SparkOS init system and all necessary files to run or build SparkOS.
## Contents
- `init` - The compiled init binary (statically linked)
- `src/` - Source code for the init system
- `scripts/` - Build and setup scripts
- `config/` - Configuration files
- `rootfs/` - Root filesystem structure
- `Makefile` - Build system
- Documentation files (README.md, ARCHITECTURE.md, etc.)
## Quick Start
### Using the Pre-built Binary
The `init` binary is already compiled and ready to use:
```bash
# Copy to your rootfs
cp init /path/to/your/rootfs/sbin/init
chmod 755 /path/to/your/rootfs/sbin/init
```
### Rebuilding from Source
If you need to rebuild:
```bash
# Build the init system
make init
# Install to rootfs
make install
```
### Creating a Bootable System
Follow the instructions in README.md to create a complete bootable system.
## System Requirements
- Linux system with kernel 3.x or later with framebuffer support
- Qt6 runtime libraries for GUI
- For building: GCC compiler, Make
## Documentation
See README.md for complete documentation, including:
- Building instructions
- Creating bootable images
- Network configuration
- Development guidelines
## Support
For issues and questions, visit: https://github.com/johndoe6345789/SparkOS

30
sparkos/config/build.conf Normal file
View File

@@ -0,0 +1,30 @@
# SparkOS Configuration
# This file defines the build configuration for SparkOS
# Target architecture
ARCH=x86_64
# Kernel version (if building custom kernel)
KERNEL_VERSION=6.1
# Image size for dd-able image
IMAGE_SIZE=512M
# Bootloader
BOOTLOADER=syslinux
# Init system
INIT=sparkos-init
# Compiler flags
CFLAGS=-Wall -O2 -static
LDFLAGS=-static
# Root filesystem location
ROOTFS=rootfs
# Build directory
BUILDDIR=build
# Output image
IMAGE=sparkos.img

View File

@@ -0,0 +1,36 @@
# Embedded bootstrap configuration for GRUB
# This config tells GRUB where to find the real configuration file
# Set proper terminal and video output
terminal_input console
terminal_output console
# Load essential modules
insmod part_gpt
insmod fat
insmod ext2
insmod normal
insmod linux
insmod all_video
insmod video_bochs
insmod video_cirrus
insmod gfxterm
# Set graphics mode for better compatibility
set gfxmode=auto
set gfxpayload=keep
# Search for ESP by label
search --no-floppy --set=root --label @ESP_LABEL@
# Try to load the main config file
if [ -e /boot/grub/grub.cfg ]; then
configfile /boot/grub/grub.cfg
else
echo "Error: Could not find /boot/grub/grub.cfg"
echo "Root device: $root"
echo "Press any key to enter GRUB command line..."
# Sleep for a very long time (interruptible by any key press)
# This provides an effective "wait for keypress" in GRUB
sleep --verbose --interruptible 99999
fi

View File

@@ -0,0 +1,42 @@
# GRUB Configuration for SparkOS
# Load essential modules
insmod part_gpt
insmod fat
insmod ext2
insmod linux
insmod all_video
insmod video_bochs
insmod video_cirrus
insmod gfxterm
# Set terminal and video modes
terminal_input console
terminal_output console
set gfxmode=auto
set gfxpayload=keep
# Boot menu settings
set timeout=5
set default=0
# Show countdown message
echo "SparkOS Boot Menu - Starting in $timeout seconds..."
menuentry "SparkOS" {
echo "Loading SparkOS kernel..."
linux /boot/vmlinuz root=LABEL=@ROOT_LABEL@ ro init=/sbin/init console=tty0 console=ttyS0,115200n8
initrd /boot/initrd.img
}
menuentry "SparkOS (Verbose Mode)" {
echo "Loading SparkOS kernel in verbose mode..."
linux /boot/vmlinuz root=LABEL=@ROOT_LABEL@ ro init=/sbin/init console=tty0 console=ttyS0,115200n8 debug loglevel=7
initrd /boot/initrd.img
}
menuentry "SparkOS (Recovery Mode)" {
echo "Loading SparkOS kernel in recovery mode..."
linux /boot/vmlinuz root=LABEL=@ROOT_LABEL@ rw init=/bin/sh console=tty0 console=ttyS0,115200n8
initrd /boot/initrd.img
}

View File

@@ -0,0 +1,23 @@
SparkOS UEFI-Bootable Image
This is a UEFI-bootable disk image with:
- GPT partition table
- EFI System Partition (ESP) with FAT32 filesystem
- GRUB UEFI bootloader
- Linux kernel
- SparkOS init system (self-contained, no external dependencies)
- Qt6 GUI application
The image can be written to a USB drive and booted on UEFI systems:
sudo dd if=sparkos.img of=/dev/sdX bs=4M status=progress
sudo sync
Boot options:
- UEFI boot support (tested on x86_64 systems)
- Automatic boot after 3 seconds
- Direct boot to Qt6 GUI (no CLI)
- Console on tty1 (for debugging only)
Philosophy: GUI-only, no CLI tools, network-first
For more information, see: https://github.com/johndoe6345789/SparkOS

View File

@@ -0,0 +1,74 @@
SparkOS UEFI-Bootable Disk Image
==================================
This package contains a UEFI-bootable disk image with SparkOS.
Files:
- sparkos.img.gz - Compressed UEFI-bootable disk image (~1GB)
What's Included:
---------------
✓ GPT partition table
✓ EFI System Partition (ESP) with FAT32 filesystem
✓ GRUB UEFI bootloader
✓ Linux kernel
✓ SparkOS init system (self-contained, no dependencies)
✓ Qt6 GUI application
✓ Minimal filesystem structure
Boot Support:
------------
✓ UEFI boot (x86_64 systems)
✓ Automatic boot after 3 seconds
✓ Direct boot to Qt6 GUI (no CLI)
✓ Console on tty1 (for debugging only)
Quick Start:
-----------
1. Decompress the image:
gunzip sparkos.img.gz
2. Write to USB drive (Linux - BE CAREFUL!):
sudo dd if=sparkos.img of=/dev/sdX bs=4M status=progress oflag=sync
WARNING: Replace /dev/sdX with your actual USB drive device.
This will DESTROY all data on the target drive!
3. Boot from USB:
- Insert the USB drive into a UEFI-capable system
- Enter BIOS/UEFI settings (usually F2, F12, DEL, or ESC at boot)
- Select the USB drive as boot device
- SparkOS should boot automatically
Advanced - Inspect Partitions:
------------------------------
To mount and inspect the partitions:
# Set up loop device
sudo losetup -fP --show sparkos.img
# Note the loop device name (e.g., /dev/loop0)
# Mount ESP (EFI System Partition)
sudo mount /dev/loop0p1 /mnt
ls -la /mnt/EFI
sudo umount /mnt
# Mount root partition
sudo mount /dev/loop0p2 /mnt
ls -la /mnt
sudo umount /mnt
# Cleanup
sudo losetup -d /dev/loop0
Documentation:
-------------
See the full documentation at:
https://github.com/johndoe6345789/SparkOS
Support:
-------
For issues and questions, visit:
https://github.com/johndoe6345789/SparkOS/issues

View File

@@ -0,0 +1,11 @@
version: '3.8'
services:
sparkos:
build:
context: .
dockerfile: Dockerfile
image: sparkos:local
container_name: sparkos-test
# The container will run the test script and exit
# Use 'docker-compose up' to test the build

41
sparkos/rootfs/README.txt Normal file
View File

@@ -0,0 +1,41 @@
SparkOS Root Filesystem
=======================
This is the root filesystem for SparkOS, a GUI-only Linux distribution.
SparkOS Philosophy:
- GUI-Only: No CLI tools, no shell, no Unix utilities
- Network-First: Networking integrated into Qt6 GUI
- Direct Kernel Interface: Qt6 communicates directly with Linux kernel
- No Unix Baggage: No users, groups, passwords, or authentication
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:
/sbin - Init binary only
/etc - Minimal configuration files
/proc, /sys, /dev - Kernel interfaces
/tmp - Temporary files
/usr - Qt6 GUI application and libraries
/var - Variable data (overlay mount)
/root - Root home directory
Network Configuration:
- Managed entirely through Qt6 GUI
- Init brings up interfaces via direct ioctl calls
- DHCP and network management handled by Qt6 NetworkManager
- /etc/resolv.conf provides fallback DNS servers
Boot Process:
1. Linux kernel loads
2. Init (PID 1) mounts filesystems
3. Init brings up network interfaces
4. Init spawns Qt6 GUI application
5. All user interaction through GUI
Note: This is a minimal, GUI-only system.
No shell, no CLI tools, no busybox.
All functionality is provided through the Qt6 GUI application.

5
sparkos/rootfs/etc/fstab Normal file
View File

@@ -0,0 +1,5 @@
# <file system> <mount point> <type> <options> <dump> <pass>
proc /proc proc defaults 0 0
sysfs /sys sysfs defaults 0 0
devtmpfs /dev devtmpfs defaults 0 0
tmpfs /tmp tmpfs defaults 0 0

View File

@@ -0,0 +1 @@
sparkos

3
sparkos/rootfs/etc/hosts Normal file
View File

@@ -0,0 +1,3 @@
127.0.0.1 localhost
127.0.1.1 sparkos
::1 localhost ip6-localhost ip6-loopback

View File

@@ -0,0 +1,10 @@
# 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

View File

@@ -0,0 +1,17 @@
# 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 ""

View File

@@ -0,0 +1,6 @@
# SparkOS DNS Configuration
# Fallback to public DNS servers for reliability
nameserver 8.8.8.8
nameserver 8.8.4.4
nameserver 1.1.1.1
nameserver 1.0.0.1

View File

@@ -0,0 +1,12 @@
# SparkOS User Shell Configuration
# Set prompt
PS1='SparkOS:\w\$ '
# Aliases
alias ll='ls -lah'
alias ..='cd ..'
# Environment
export EDITOR=vi
export PAGER=less

View File

@@ -0,0 +1,50 @@
#!/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

View File

@@ -0,0 +1,12 @@
# SparkOS Root Shell Configuration
# Set prompt
PS1='SparkOS:\w# '
# Aliases
alias ll='ls -lah'
alias ..='cd ..'
# Environment
export EDITOR=vi
export PAGER=less

67
sparkos/scripts/build-image.sh Executable file
View File

@@ -0,0 +1,67 @@
#!/bin/bash
# Build SparkOS disk image using Docker
# This script builds a .img file without requiring root on the host
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
OUTPUT_DIR="$PROJECT_ROOT/release"
echo "SparkOS Disk Image Builder (Docker)"
echo "===================================="
echo ""
# Clean previous build
if [ -f "$OUTPUT_DIR/sparkos.img.gz" ]; then
echo "Cleaning previous image..."
rm -f "$OUTPUT_DIR/sparkos.img.gz"
fi
mkdir -p "$OUTPUT_DIR"
echo "Building disk image using Docker..."
echo "This may take a few minutes..."
echo ""
# Build the image builder container
cd "$PROJECT_ROOT"
docker buildx build \
--file Dockerfile.image \
--target image-builder \
--tag sparkos:image-builder \
--load \
.
# Extract the image
echo ""
echo "Extracting disk image..."
CONTAINER_ID=$(docker create sparkos:image-builder)
docker cp "$CONTAINER_ID:/output/sparkos.img.gz" "$OUTPUT_DIR/sparkos.img.gz"
docker rm "$CONTAINER_ID" > /dev/null
echo ""
echo "SUCCESS! Disk image created:"
echo " Location: $OUTPUT_DIR/sparkos.img.gz"
echo " Size: $(du -h "$OUTPUT_DIR/sparkos.img.gz" | cut -f1)"
echo ""
# Show decompressed size
echo "Decompressed size:"
DECOMPRESSED_SIZE=$(gunzip -l "$OUTPUT_DIR/sparkos.img.gz" | tail -1 | awk '{print $2}')
echo " $(numfmt --to=iec-i --suffix=B $DECOMPRESSED_SIZE)"
echo ""
echo "To write to a USB drive:"
echo " gunzip $OUTPUT_DIR/sparkos.img.gz"
echo " sudo dd if=$OUTPUT_DIR/sparkos.img of=/dev/sdX bs=4M status=progress"
echo ""
echo "WARNING: Replace /dev/sdX with your actual USB device!"
echo " This will DESTROY all data on the target drive!"
echo ""
echo "To inspect the image:"
echo " gunzip -c $OUTPUT_DIR/sparkos.img.gz > /tmp/sparkos.img"
echo " sudo mount -o loop /tmp/sparkos.img /mnt"
echo " ls -la /mnt"
echo " sudo umount /mnt"

37
sparkos/scripts/build.sh Executable file
View File

@@ -0,0 +1,37 @@
#!/bin/bash
# Quick build script for SparkOS development
# Note: This script runs on the host system and uses bash for ${BASH_SOURCE}
set -e
PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$PROJECT_ROOT"
echo "SparkOS Quick Build"
echo "==================="
echo ""
# Build init
echo "Building init system..."
make init
# Setup rootfs structure
echo ""
echo "Setting up root filesystem..."
./scripts/setup_rootfs.sh
# Install init
echo ""
echo "Installing init to rootfs..."
make install
echo ""
echo "Build complete!"
echo ""
echo "Next steps to create a full bootable system:"
echo " 1. Build Qt6 GUI: make gui"
echo " 2. Add a Linux kernel to rootfs/boot/vmlinuz"
echo " 3. Run: sudo make image"
echo ""
echo "Philosophy: No CLI tools, GUI-only experience"
echo ""

132
sparkos/scripts/create_image.sh Executable file
View File

@@ -0,0 +1,132 @@
#!/bin/bash
# SparkOS Image Creation Script
# Creates a bootable dd-able disk image
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
IMAGE_FILE="$PROJECT_ROOT/sparkos.img"
IMAGE_SIZE="512M"
MOUNT_POINT="/tmp/sparkos_mount"
ROOTFS_DIR="$PROJECT_ROOT/rootfs"
LOOP_DEV=""
# Cleanup function
cleanup() {
local exit_code=$?
echo "Cleaning up..."
# Unmount if mounted
if mountpoint -q "$MOUNT_POINT" 2>/dev/null; then
umount "$MOUNT_POINT" 2>/dev/null || true
fi
# Remove mount point
if [ -d "$MOUNT_POINT" ]; then
rmdir "$MOUNT_POINT" 2>/dev/null || true
fi
# Detach loop device
if [ -n "$LOOP_DEV" ] && losetup "$LOOP_DEV" &>/dev/null; then
losetup -d "$LOOP_DEV" 2>/dev/null || true
fi
if [ $exit_code -ne 0 ]; then
echo "ERROR: Image creation failed"
fi
exit $exit_code
}
# Set trap for cleanup on exit, interrupt, or error
trap cleanup EXIT INT TERM
echo "SparkOS Image Builder"
echo "====================="
echo ""
# Check if running as root
if [ "$(id -u)" -ne 0 ]; then
echo "ERROR: This script must be run as root"
echo "Usage: sudo $0"
exit 1
fi
# Check for required tools
REQUIRED_TOOLS="dd losetup mkfs.ext4 syslinux"
for tool in $REQUIRED_TOOLS; do
if ! command -v "$tool" &> /dev/null; then
echo "ERROR: Required tool '$tool' is not installed"
exit 1
fi
done
echo "Creating disk image ($IMAGE_SIZE)..."
dd if=/dev/zero of="$IMAGE_FILE" bs=1M count=512 status=progress
echo "Setting up loop device..."
LOOP_DEV=$(losetup -f)
losetup "$LOOP_DEV" "$IMAGE_FILE"
echo "Creating partition table..."
parted -s "$LOOP_DEV" mklabel msdos
parted -s "$LOOP_DEV" mkpart primary ext4 1MiB 100%
parted -s "$LOOP_DEV" set 1 boot on
# Reload partition table
partprobe "$LOOP_DEV" 2>/dev/null || true
sleep 1
# Get partition device
PART_DEV="${LOOP_DEV}p1"
if [ ! -e "$PART_DEV" ]; then
PART_DEV="${LOOP_DEV}1"
fi
echo "Creating ext4 filesystem..."
mkfs.ext4 -F "$PART_DEV"
echo "Mounting filesystem..."
mkdir -p "$MOUNT_POINT"
mount "$PART_DEV" "$MOUNT_POINT"
echo "Copying rootfs..."
if [ -d "$ROOTFS_DIR" ]; then
cp -a "$ROOTFS_DIR"/* "$MOUNT_POINT/"
else
echo "WARNING: rootfs directory not found, creating minimal structure"
mkdir -p "$MOUNT_POINT"/{bin,sbin,etc,proc,sys,dev,tmp,usr/{bin,sbin,lib},var,root,home}
fi
echo "Installing bootloader..."
mkdir -p "$MOUNT_POINT/boot/syslinux"
# Create syslinux config
cat > "$MOUNT_POINT/boot/syslinux/syslinux.cfg" << 'EOF'
DEFAULT linux
PROMPT 0
TIMEOUT 50
LABEL linux
SAY Booting SparkOS...
KERNEL /boot/vmlinuz
APPEND ro root=/dev/sda1 init=/sbin/init console=tty1
EOF
# Install syslinux
syslinux --install "$PART_DEV"
# Install MBR
dd if=/usr/lib/syslinux/mbr/mbr.bin of="$LOOP_DEV" bs=440 count=1 conv=notrunc 2>/dev/null || \
dd if=/usr/share/syslinux/mbr.bin of="$LOOP_DEV" bs=440 count=1 conv=notrunc 2>/dev/null || \
echo "WARNING: Could not install MBR, you may need to do this manually"
echo ""
echo "SUCCESS! Bootable image created: $IMAGE_FILE"
echo ""
echo "To write to a USB drive:"
echo " sudo dd if=$IMAGE_FILE of=/dev/sdX bs=4M status=progress"
echo ""
echo "WARNING: Replace /dev/sdX with your actual USB drive device"
echo " This will DESTROY all data on the target drive!"

View File

@@ -0,0 +1,148 @@
#!/bin/bash
# Create UEFI-bootable SparkOS image with GPT partition table
set -e
mkdir -p /output /staging/esp /staging/root
echo "=== Creating UEFI-bootable SparkOS image with GRUB ==="
# Create 1GB disk image (larger for kernel + bootloader)
dd if=/dev/zero of=/output/sparkos.img bs=1M count=1024
# Create GPT partition table
echo "Creating GPT partition table..."
parted -s /output/sparkos.img mklabel gpt
# Create EFI System Partition (ESP) - 200MB, FAT32
echo "Creating EFI System Partition..."
parted -s /output/sparkos.img mkpart ESP fat32 1MiB 201MiB
parted -s /output/sparkos.img set 1 esp on
# Create root partition - remaining space, ext4
echo "Creating root partition..."
parted -s /output/sparkos.img mkpart primary ext4 201MiB 100%
# Use libguestfs to format and populate partitions without loop devices
echo "Formatting partitions using guestfish..."
guestfish -a /output/sparkos.img <<'EOF'
run
mkfs vfat /dev/sda1 label:SPARKOSEFI
mkfs ext4 /dev/sda2 label:SparkOS
mount /dev/sda2 /
mkdir-p /boot
EOF
# Prepare ESP contents
echo "Preparing ESP contents..."
# Prepare ESP contents
echo "Preparing ESP contents..."
mkdir -p /staging/esp/EFI/BOOT
mkdir -p /staging/esp/boot/grub
# Create GRUB EFI binary using grub-mkstandalone
grub-mkstandalone \
--format=x86_64-efi \
--output=/staging/esp/EFI/BOOT/BOOTX64.EFI \
--locales="" \
--fonts="" \
"boot/grub/grub.cfg=/dev/null"
# Find the kernel
KERNEL_PATH=$(find /kernel/boot -name "vmlinuz-*" | head -1)
KERNEL_VERSION=$(basename $KERNEL_PATH | sed 's/vmlinuz-//')
INITRD_PATH=$(find /kernel/boot -name "initrd.img-*" | head -1)
# Copy kernel and initrd to staging
echo "Copying kernel to staging..."
cp $KERNEL_PATH /staging/esp/boot/vmlinuz
# Ensure initrd exists (required for booting)
if [ ! -f "$INITRD_PATH" ]; then
echo "ERROR: initrd not found. The kernel requires an initrd to boot."
echo "Expected to find: initrd.img-* in /kernel/boot/"
exit 1
fi
echo "Copying initrd to staging..."
cp $INITRD_PATH /staging/esp/boot/initrd.img
# Create GRUB configuration
printf '%s\n' \
'set timeout=3' \
'set default=0' \
'' \
'menuentry "SparkOS" {' \
' linux /boot/vmlinuz root=LABEL=SparkOS rw init=/sbin/init console=tty1 quiet' \
' initrd /boot/initrd.img' \
'}' \
> /staging/esp/boot/grub/grub.cfg
# Prepare root filesystem contents
echo "Preparing root filesystem..."
mkdir -p /staging/root/{bin,sbin,etc,proc,sys,dev,tmp,usr/{bin,sbin,lib,lib64},var/{log,run},root,home/spark,boot}
# Install SparkOS init
cp /build/init /staging/root/sbin/init
chmod 755 /staging/root/sbin/init
# Create system configuration files
echo "sparkos" > /staging/root/etc/hostname
echo "127.0.0.1 localhost" > /staging/root/etc/hosts
echo "127.0.1.1 sparkos" >> /staging/root/etc/hosts
# Copy README to root partition
cp /build/config/image-readme.txt /staging/root/README.txt
# Copy ESP contents to the image
echo "Populating EFI System Partition..."
guestfish -a /output/sparkos.img <<'EOF'
run
mount /dev/sda1 /
mkdir-p /EFI
mkdir-p /EFI/BOOT
mkdir-p /boot
mkdir-p /boot/grub
EOF
# Copy files using guestfish
echo "Copying bootloader files..."
guestfish -a /output/sparkos.img -m /dev/sda1 <<EOF
copy-in /staging/esp/EFI/BOOT/BOOTX64.EFI /EFI/BOOT/
copy-in /staging/esp/boot/vmlinuz /boot/
copy-in /staging/esp/boot/initrd.img /boot/
EOF
guestfish -a /output/sparkos.img -m /dev/sda1 <<EOF
copy-in /staging/esp/boot/grub/grub.cfg /boot/grub/
EOF
# Copy root filesystem contents to the image
echo "Populating root filesystem..."
guestfish -a /output/sparkos.img -m /dev/sda2 <<'EOF'
copy-in /staging/root/bin /
copy-in /staging/root/sbin /
copy-in /staging/root/etc /
copy-in /staging/root/usr /
copy-in /staging/root/var /
copy-in /staging/root/root /
copy-in /staging/root/home /
copy-in /staging/root/README.txt /
mkdir-p /proc
mkdir-p /sys
mkdir-p /dev
mkdir-p /tmp
mkdir-p /boot
chmod 0755 /tmp
chmod 0755 /sbin/init
chmod 0755 /bin/busybox
EOF
# Finalize
echo "Finalizing image..."
sync
# Compress the image
echo "Compressing image..."
gzip -9 /output/sparkos.img
echo "UEFI-bootable image created: /output/sparkos.img.gz"

View File

@@ -0,0 +1,129 @@
#!/bin/bash
# Create UEFI-bootable SparkOS image with GPT partition table
# This version uses mtools and mke2fs to avoid needing loop devices
set -e
# Configuration
ESP_LABEL="SPARKOSEFI"
ROOT_LABEL="SparkOS"
mkdir -p /output /staging/esp /staging/root
echo "=== Creating UEFI-bootable SparkOS image with GRUB ==="
# Prepare ESP contents first
echo "Preparing ESP contents..."
mkdir -p /staging/esp/EFI/BOOT
mkdir -p /staging/esp/boot/grub
# Create minimal embedded GRUB configuration from template
sed "s/@ESP_LABEL@/$ESP_LABEL/g" /build/config/grub-embedded.cfg.in > /tmp/embedded_grub.cfg
# Create GRUB EFI binary using grub-mkstandalone with embedded bootstrap config
# Include essential modules for better hardware compatibility
grub-mkstandalone \
--format=x86_64-efi \
--output=/staging/esp/EFI/BOOT/BOOTX64.EFI \
--locales="" \
--fonts="" \
--modules="part_gpt part_msdos fat ext2 normal linux \
all_video video_bochs video_cirrus gfxterm \
search search_label search_fs_uuid" \
"boot/grub/grub.cfg=/tmp/embedded_grub.cfg"
# Find the kernel
KERNEL_PATH=$(find /kernel/boot -name "vmlinuz-*" | head -1)
KERNEL_VERSION=$(basename $KERNEL_PATH | sed 's/vmlinuz-//')
INITRD_PATH=$(find /kernel/boot -name "initrd.img-*" | head -1)
# Copy kernel and initrd to staging
echo "Copying kernel to staging..."
cp $KERNEL_PATH /staging/esp/boot/vmlinuz
# Ensure initrd exists (required for booting)
if [ ! -f "$INITRD_PATH" ]; then
echo "ERROR: initrd not found. The kernel requires an initrd to boot."
echo "Expected to find: initrd.img-* in /kernel/boot/"
exit 1
fi
echo "Copying initrd to staging..."
cp $INITRD_PATH /staging/esp/boot/initrd.img
# Create GRUB configuration from template
sed "s/@ROOT_LABEL@/$ROOT_LABEL/g" /build/config/grub.cfg.in > /staging/esp/boot/grub/grub.cfg
# Prepare root filesystem contents
echo "Preparing root filesystem..."
mkdir -p /staging/root/{bin,sbin,etc,proc,sys,dev,tmp,usr/{bin,sbin,lib,lib64},var/{log,run},root,home/spark,boot}
# Install SparkOS init
cp /build/init /staging/root/sbin/init
chmod 755 /staging/root/sbin/init
# Create system configuration files
echo "sparkos" > /staging/root/etc/hostname
echo "127.0.0.1 localhost" > /staging/root/etc/hosts
echo "127.0.1.1 sparkos" >> /staging/root/etc/hosts
# Copy README to root partition
cp /build/config/image-readme.txt /staging/root/README.txt
# Create 1GB disk image
echo "Creating disk image..."
dd if=/dev/zero of=/output/sparkos.img bs=1M count=1024
# Create GPT partition table using sgdisk
echo "Creating GPT partition table..."
sgdisk -Z /output/sparkos.img 2>/dev/null || true
sgdisk -n 1:2048:411647 -t 1:ef00 -c 1:"EFI System" /output/sparkos.img
sgdisk -n 2:411648:0 -t 2:8300 -c 2:"Linux filesystem" /output/sparkos.img
# Extract partition regions using dd
echo "Extracting partition regions..."
dd if=/output/sparkos.img of=/tmp/esp.img bs=512 skip=2048 count=409600 2>/dev/null
# Calculate exact size for root partition
ROOT_START=411648
ROOT_END=$(sgdisk -p /output/sparkos.img 2>/dev/null | grep "^ 2" | awk '{print $3}')
ROOT_SIZE=$((ROOT_END - ROOT_START + 1))
echo "Root partition: start=$ROOT_START, end=$ROOT_END, size=$ROOT_SIZE sectors"
dd if=/output/sparkos.img of=/tmp/root.img bs=512 skip=$ROOT_START count=$ROOT_SIZE 2>/dev/null
# Format ESP partition (FAT32)
echo "Formatting EFI System Partition (FAT32)..."
mkfs.vfat -F 32 -n "$ESP_LABEL" /tmp/esp.img >/dev/null
# Populate ESP using mtools (no mount needed!)
echo "Populating ESP with bootloader and kernel..."
export MTOOLS_SKIP_CHECK=1
mmd -i /tmp/esp.img ::/EFI
mmd -i /tmp/esp.img ::/EFI/BOOT
mmd -i /tmp/esp.img ::/boot
mmd -i /tmp/esp.img ::/boot/grub
mcopy -i /tmp/esp.img /staging/esp/EFI/BOOT/BOOTX64.EFI ::/EFI/BOOT/
mcopy -i /tmp/esp.img /staging/esp/boot/vmlinuz ::/boot/
mcopy -i /tmp/esp.img /staging/esp/boot/initrd.img ::/boot/
mcopy -i /tmp/esp.img /staging/esp/boot/grub/grub.cfg ::/boot/grub/
# Format root partition (ext4) with directory contents (no mount needed!)
echo "Formatting root partition (ext4) and populating..."
mke2fs -t ext4 -L "$ROOT_LABEL" -d /staging/root /tmp/root.img >/dev/null 2>&1
# Write partitions back to image
echo "Writing partitions to image..."
dd if=/tmp/esp.img of=/output/sparkos.img bs=512 seek=2048 count=409600 conv=notrunc 2>/dev/null
dd if=/tmp/root.img of=/output/sparkos.img bs=512 seek=$ROOT_START count=$ROOT_SIZE conv=notrunc 2>/dev/null
# Clean up temporary files
rm -f /tmp/esp.img /tmp/root.img
# Finalize
echo "Finalizing image..."
sync
# Compress the image
echo "Compressing image..."
gzip -9 /output/sparkos.img
echo "UEFI-bootable image created: /output/sparkos.img.gz"

View File

@@ -0,0 +1,71 @@
#!/bin/bash
# Download a minimal Linux kernel for UEFI image
set -e
echo "=== Downloading Linux kernel from Ubuntu repositories ==="
mkdir -p /kernel
apt-get update
# Install initramfs-tools for generating initrd
echo "Installing initramfs-tools..."
apt-get install -y initramfs-tools
# Get the actual kernel package name (not the metapackage)
echo "Finding latest kernel package..."
KERNEL_PKG=$(apt-cache depends linux-image-generic | grep -E 'Depends.*linux-image-[0-9]' | head -1 | awk '{print $2}')
if [ -z "$KERNEL_PKG" ]; then
echo "ERROR: Could not determine kernel package name"
exit 1
fi
echo "Downloading kernel package: $KERNEL_PKG"
apt-get download "$KERNEL_PKG"
# Extract the kernel package to /kernel
echo "Extracting kernel..."
dpkg -x "${KERNEL_PKG}"*.deb /kernel
# Verify kernel was extracted
if [ ! -d /kernel/boot ]; then
echo "ERROR: Kernel boot directory not found after extraction"
exit 1
fi
KERNEL_FILE=$(find /kernel/boot -name "vmlinuz-*" | head -1)
if [ -z "$KERNEL_FILE" ]; then
echo "ERROR: No kernel image found"
exit 1
fi
echo "Kernel extracted successfully: $KERNEL_FILE"
# Extract kernel version from the kernel filename
KERNEL_VERSION=$(basename "$KERNEL_FILE" | sed 's/vmlinuz-//')
echo "Kernel version: $KERNEL_VERSION"
# Copy kernel modules to system location so mkinitramfs can find them
echo "Copying kernel modules to system location..."
if [ -d "/kernel/lib/modules/${KERNEL_VERSION}" ]; then
cp -r "/kernel/lib/modules/${KERNEL_VERSION}" /lib/modules/
else
echo "WARNING: No modules found for kernel ${KERNEL_VERSION}"
fi
# Generate initrd using mkinitramfs
echo "Generating initrd for kernel version $KERNEL_VERSION..."
mkinitramfs -o "/kernel/boot/initrd.img-${KERNEL_VERSION}" "${KERNEL_VERSION}"
# Verify initrd was created
if [ ! -f "/kernel/boot/initrd.img-${KERNEL_VERSION}" ]; then
echo "ERROR: Failed to generate initrd"
exit 1
fi
echo "Initrd generated successfully: /kernel/boot/initrd.img-${KERNEL_VERSION}"
ls -lh /kernel/boot/
# Clean up
rm -rf /var/lib/apt/lists/* "${KERNEL_PKG}"*.deb

View File

@@ -0,0 +1,29 @@
#!/bin/bash
# Install required tools for building UEFI-bootable SparkOS image
set -e
apt-get update
apt-get install -y \
gcc \
g++ \
make \
cmake \
qt6-base-dev \
qt6-base-dev-tools \
libqt6core6 \
libqt6gui6 \
libqt6widgets6 \
libgl1-mesa-dev \
libglu1-mesa-dev \
dosfstools \
mtools \
e2fsprogs \
parted \
gdisk \
grub-efi-amd64-bin \
grub-common \
wget \
kmod \
udev
rm -rf /var/lib/apt/lists/*

View File

@@ -0,0 +1,6 @@
#!/bin/sh
# Install runtime packages for Alpine-based Docker image
set -e
apk add --no-cache file

183
sparkos/scripts/docker-release.sh Executable file
View File

@@ -0,0 +1,183 @@
#!/bin/bash
# SparkOS Docker-based Release Builder
# Build release artifacts using Docker (no root required)
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
RELEASE_DIR="$PROJECT_ROOT/release"
VERSION="${1:-dev}"
echo "SparkOS Docker Release Builder"
echo "=============================="
echo ""
echo "Version: $VERSION"
echo ""
# Clean previous release
if [ -d "$RELEASE_DIR" ]; then
echo "Cleaning previous release..."
rm -rf "$RELEASE_DIR"
fi
mkdir -p "$RELEASE_DIR"
# Build using Docker (multi-stage build)
echo "Building init binary using Docker..."
docker build -t sparkos:build-temp --target builder "$PROJECT_ROOT"
# Extract the built binary
echo "Extracting init binary..."
CONTAINER_ID=$(docker create sparkos:build-temp)
docker cp "$CONTAINER_ID:/build/init" "$RELEASE_DIR/init"
docker rm "$CONTAINER_ID" > /dev/null
# Verify the binary
echo ""
echo "Verifying init binary..."
if [ ! -f "$RELEASE_DIR/init" ]; then
echo "ERROR: Failed to extract init binary"
exit 1
fi
ls -lh "$RELEASE_DIR/init"
file "$RELEASE_DIR/init"
# Create release package structure
echo ""
echo "Creating release package..."
mkdir -p "$RELEASE_DIR/sparkos"
# Copy compiled binary
cp "$RELEASE_DIR/init" "$RELEASE_DIR/sparkos/"
# Copy essential files
cp "$PROJECT_ROOT/README.md" "$RELEASE_DIR/sparkos/"
cp "$PROJECT_ROOT/LICENSE" "$RELEASE_DIR/sparkos/"
cp "$PROJECT_ROOT/ARCHITECTURE.md" "$RELEASE_DIR/sparkos/"
cp "$PROJECT_ROOT/CONTRIBUTING.md" "$RELEASE_DIR/sparkos/"
cp "$PROJECT_ROOT/Makefile" "$RELEASE_DIR/sparkos/"
cp "$PROJECT_ROOT/Dockerfile" "$RELEASE_DIR/sparkos/"
# Copy source for reference
cp -r "$PROJECT_ROOT/src" "$RELEASE_DIR/sparkos/"
# Copy scripts
cp -r "$PROJECT_ROOT/scripts" "$RELEASE_DIR/sparkos/"
# Copy config
cp -r "$PROJECT_ROOT/config" "$RELEASE_DIR/sparkos/"
# Copy rootfs structure (without generated content)
mkdir -p "$RELEASE_DIR/sparkos/rootfs"
for dir in etc root home; do
if [ -d "$PROJECT_ROOT/rootfs/$dir" ]; then
cp -r "$PROJECT_ROOT/rootfs/$dir" "$RELEASE_DIR/sparkos/rootfs/"
fi
done
# Create README for the release
cat > "$RELEASE_DIR/sparkos/RELEASE_README.md" << 'EOF'
# SparkOS Release Package
This package contains the compiled SparkOS init system and all necessary files to run or build SparkOS.
## Contents
- `init` - The compiled init binary (statically linked)
- `src/` - Source code for the init system
- `scripts/` - Build and setup scripts
- `config/` - Configuration files
- `rootfs/` - Root filesystem structure
- `Dockerfile` - Docker image definition
- `Makefile` - Build system
- Documentation files (README.md, ARCHITECTURE.md, etc.)
## Quick Start
### Using the Pre-built Binary
The `init` binary is already compiled and ready to use:
```bash
# Copy to your rootfs
cp init /path/to/your/rootfs/sbin/init
chmod 755 /path/to/your/rootfs/sbin/init
```
### Using Docker
The easiest way to test SparkOS:
```bash
# Build the Docker image
docker build -t sparkos .
# Run the test environment
docker run --rm sparkos
```
### Rebuilding from Source
If you need to rebuild:
```bash
# Build the init system
make init
# Install to rootfs
make install
```
## Using Docker for Releases
Build release artifacts without needing root or special tools:
```bash
# Build release package
./scripts/docker-release.sh v1.0.0
# The release package will be in release/sparkos-release.zip
```
## System Requirements
- Linux system with kernel 3.x or later with framebuffer support
- Qt6 runtime libraries for GUI
- For building: Docker or GCC compiler and Make
## Documentation
See README.md for complete documentation, including:
- Building instructions
- Docker usage
- Network configuration
- Development guidelines
## Support
For issues and questions, visit: https://github.com/johndoe6345789/SparkOS
EOF
# Create release archive
echo ""
echo "Creating release archive..."
cd "$RELEASE_DIR"
zip -q -r "sparkos-release.zip" sparkos/
cd "$PROJECT_ROOT"
echo ""
echo "SUCCESS! Release package created:"
echo " Location: $RELEASE_DIR/sparkos-release.zip"
echo " Size: $(du -h "$RELEASE_DIR/sparkos-release.zip" | cut -f1)"
echo ""
echo "Contents:"
ls -lh "$RELEASE_DIR/sparkos-release.zip"
echo ""
echo "To verify the contents:"
echo " unzip -l $RELEASE_DIR/sparkos-release.zip | head -40"
echo ""
echo "To test the Docker image:"
echo " docker build -t sparkos:$VERSION ."
echo " docker run --rm sparkos:$VERSION"

View File

@@ -0,0 +1,19 @@
#!/bin/sh
# Set up basic configuration files for SparkOS
set -e
# Create hostname
echo "sparkos" > /sparkos/rootfs/etc/hostname
# Create hosts file
echo "127.0.0.1 localhost" > /sparkos/rootfs/etc/hosts
echo "127.0.1.1 sparkos" >> /sparkos/rootfs/etc/hosts
# Create passwd file
echo "root:x:0:0:root:/root:/bin/sh" > /sparkos/rootfs/etc/passwd
echo "spark:x:1000:1000:SparkOS User:/home/spark:/bin/sh" >> /sparkos/rootfs/etc/passwd
# Create group file
echo "root:x:0:" > /sparkos/rootfs/etc/group
echo "spark:x:1000:" >> /sparkos/rootfs/etc/group

View File

@@ -0,0 +1,25 @@
#!/bin/sh
# Create minimal rootfs structure for SparkOS
set -e
# Create minimal rootfs structure
mkdir -p /sparkos/rootfs/bin \
/sparkos/rootfs/sbin \
/sparkos/rootfs/etc \
/sparkos/rootfs/proc \
/sparkos/rootfs/sys \
/sparkos/rootfs/dev \
/sparkos/rootfs/tmp \
/sparkos/rootfs/usr/bin \
/sparkos/rootfs/usr/sbin \
/sparkos/rootfs/usr/lib \
/sparkos/rootfs/var/log \
/sparkos/rootfs/var/run \
/sparkos/rootfs/root \
/sparkos/rootfs/home/spark
# Set proper permissions
chmod 1777 /sparkos/rootfs/tmp
chmod 700 /sparkos/rootfs/root
chmod 755 /sparkos/rootfs/home/spark

228
sparkos/scripts/install.sh Executable file
View File

@@ -0,0 +1,228 @@
#!/bin/bash
# SparkOS Installation Script
# Writes the SparkOS image to a target drive
# Note: This script runs on the host system and uses bash for ${BASH_SOURCE}
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
IMAGE_FILE="$PROJECT_ROOT/sparkos.img"
# Cleanup function
cleanup() {
local exit_code=$?
if [ $exit_code -ne 0 ]; then
echo ""
echo "ERROR: Installation failed"
fi
exit $exit_code
}
# Set trap for cleanup on exit, interrupt, or error
trap cleanup EXIT INT TERM
# Print usage
usage() {
cat << EOF
SparkOS Installation Script
===========================
Usage: $0 <target_drive>
Arguments:
target_drive Block device to install to (e.g., /dev/sdb, /dev/nvme1n1)
Example:
sudo $0 /dev/sdb
sudo $0 /dev/nvme1n1
WARNING: This will DESTROY all data on the target drive!
EOF
exit 1
}
# Print header
echo "SparkOS Installation Script"
echo "==========================="
echo ""
# Check if running as root
if [ "$(id -u)" -ne 0 ]; then
echo "ERROR: This script must be run as root"
echo "Usage: sudo $0 <target_drive>"
exit 1
fi
# Check for target drive argument
if [ $# -eq 0 ]; then
echo "ERROR: No target drive specified"
echo ""
usage
fi
TARGET_DRIVE="$1"
# Validate image file exists
if [ ! -f "$IMAGE_FILE" ]; then
echo "ERROR: SparkOS image not found: $IMAGE_FILE"
echo ""
echo "Please build the image first:"
echo " make all"
echo " sudo make image"
exit 1
fi
# Validate target drive exists
if [ ! -e "$TARGET_DRIVE" ]; then
echo "ERROR: Target drive does not exist: $TARGET_DRIVE"
echo ""
echo "Available block devices:"
lsblk -d -o NAME,SIZE,TYPE,MODEL | grep -E '^NAME|disk' || echo " No block devices found"
exit 1
fi
# Validate target is a block device
if [ ! -b "$TARGET_DRIVE" ]; then
echo "ERROR: Target is not a block device: $TARGET_DRIVE"
echo ""
echo "Please specify a block device (e.g., /dev/sdb, /dev/nvme1n1)"
exit 1
fi
# Check for required tool
if ! command -v dd &> /dev/null; then
echo "ERROR: Required tool 'dd' is not installed"
exit 1
fi
# Get drive information
DRIVE_SIZE=$(lsblk -b -d -n -o SIZE "$TARGET_DRIVE" 2>/dev/null || echo "unknown")
DRIVE_MODEL=$(lsblk -d -n -o MODEL "$TARGET_DRIVE" 2>/dev/null || echo "unknown")
IMAGE_SIZE=$(stat -c%s "$IMAGE_FILE" 2>/dev/null || echo "unknown")
# Check if target drive is large enough
if [ "$DRIVE_SIZE" != "unknown" ] && [ "$IMAGE_SIZE" != "unknown" ]; then
if [ "$DRIVE_SIZE" -lt "$IMAGE_SIZE" ]; then
echo "ERROR: Target drive is too small"
echo " Drive size: $(numfmt --to=iec-i --suffix=B $DRIVE_SIZE 2>/dev/null || echo $DRIVE_SIZE)"
echo " Image size: $(numfmt --to=iec-i --suffix=B $IMAGE_SIZE 2>/dev/null || echo $IMAGE_SIZE)"
exit 1
fi
fi
# Display warning and drive information
echo "⚠️ WARNING: DATA DESTRUCTION IMMINENT ⚠️"
echo ""
echo "This will completely erase all data on the target drive!"
echo ""
echo "Target drive information:"
echo " Device: $TARGET_DRIVE"
echo " Model: $DRIVE_MODEL"
if [ "$DRIVE_SIZE" != "unknown" ]; then
echo " Size: $(numfmt --to=iec-i --suffix=B $DRIVE_SIZE 2>/dev/null || echo $DRIVE_SIZE)"
fi
echo ""
echo "Image information:"
echo " File: $IMAGE_FILE"
if [ "$IMAGE_SIZE" != "unknown" ]; then
echo " Size: $(numfmt --to=iec-i --suffix=B $IMAGE_SIZE 2>/dev/null || echo $IMAGE_SIZE)"
fi
echo ""
# Show mounted partitions on target drive
MOUNTED=$(lsblk -n -o MOUNTPOINT "$TARGET_DRIVE" 2>/dev/null | grep -v '^[[:space:]]*$' || true)
if [ -n "$MOUNTED" ]; then
echo "WARNING: The following partitions on $TARGET_DRIVE are currently mounted:"
lsblk -o NAME,MOUNTPOINT "$TARGET_DRIVE"
echo ""
echo "Please unmount all partitions before proceeding"
exit 1
fi
# Require user confirmation
echo "Are you absolutely sure you want to proceed?"
echo -n "Type 'YES' (in all caps) to confirm: "
read CONFIRMATION
if [ "$CONFIRMATION" != "YES" ]; then
echo ""
echo "Installation cancelled by user"
exit 0
fi
echo ""
echo "Starting installation..."
echo ""
# Unmount any partitions (just to be safe)
# Use lsblk to get actual partition names (works for all device types including NVMe)
PARTITIONS=$(lsblk -ln -o NAME "$TARGET_DRIVE" 2>/dev/null | tail -n +2 | sed 's|^|/dev/|' || true)
if [ -n "$PARTITIONS" ]; then
for part in $PARTITIONS; do
if mountpoint -q "$part" 2>/dev/null; then
echo "Unmounting $part..."
umount "$part" 2>/dev/null || true
fi
done
fi
# Write image to drive with progress
echo "Writing SparkOS image to $TARGET_DRIVE..."
echo "This may take several minutes..."
echo ""
if dd if="$IMAGE_FILE" of="$TARGET_DRIVE" bs=4M status=progress conv=fsync 2>&1; then
echo ""
echo "Image write completed successfully"
else
echo ""
echo "ERROR: Failed to write image to drive"
exit 1
fi
# Sync to ensure all data is written
echo ""
echo "Syncing data to disk..."
sync
# Verify installation by reading back the first few blocks
echo "Verifying installation..."
VERIFY_BLOCKS=1024
VERIFY_TMP=$(mktemp -t sparkos_verify.XXXXXXXX)
SOURCE_TMP=$(mktemp -t sparkos_source.XXXXXXXX)
# Ensure temp files are cleaned up on exit
trap "rm -f $VERIFY_TMP $SOURCE_TMP; cleanup" EXIT INT TERM
dd if="$TARGET_DRIVE" of="$VERIFY_TMP" bs=512 count=$VERIFY_BLOCKS status=none 2>/dev/null
dd if="$IMAGE_FILE" of="$SOURCE_TMP" bs=512 count=$VERIFY_BLOCKS status=none 2>/dev/null
if cmp -s "$VERIFY_TMP" "$SOURCE_TMP"; then
echo "✓ Verification successful - installation completed!"
else
echo "✗ Verification failed - installation may be corrupted"
rm -f "$VERIFY_TMP" "$SOURCE_TMP"
exit 1
fi
# Clean up verification files
rm -f "$VERIFY_TMP" "$SOURCE_TMP"
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "SUCCESS! SparkOS has been installed to $TARGET_DRIVE"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
echo "You can now:"
echo " 1. Safely remove the drive"
echo " 2. Boot from the drive"
echo " 3. Log in as user 'spark'"
echo ""
echo "First boot instructions:"
echo " - The system will boot with wired networking enabled"
echo " - Default user: spark (full sudo access)"
echo " - Run ~/clone-sparkos.sh to install spark CLI"
echo " - Use spark CLI to configure WiFi and system"
echo ""

120
sparkos/scripts/setup_rootfs.sh Executable file
View File

@@ -0,0 +1,120 @@
#!/bin/bash
# SparkOS Setup Script
# Sets up a minimal rootfs for GUI-only SparkOS
# Note: This script runs on the host system and uses bash for ${BASH_SOURCE}
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
ROOTFS_DIR="$PROJECT_ROOT/rootfs"
echo "SparkOS Root Filesystem Setup"
echo "=============================="
echo ""
# Create directory structure
echo "Creating directory structure..."
mkdir -p "$ROOTFS_DIR"/{sbin,etc,proc,sys,dev,tmp,usr/{bin,sbin,lib,lib64},var,root}
mkdir -p "$ROOTFS_DIR/var"/{log,run}
# Set permissions
chmod 1777 "$ROOTFS_DIR/tmp"
chmod 700 "$ROOTFS_DIR/root"
# Create basic config files
echo "Creating configuration files..."
# /etc/hostname
echo "sparkos" > "$ROOTFS_DIR/etc/hostname"
# /etc/hosts
cat > "$ROOTFS_DIR/etc/hosts" << 'EOF'
127.0.0.1 localhost
127.0.1.1 sparkos
::1 localhost ip6-localhost ip6-loopback
EOF
# /etc/fstab
cat > "$ROOTFS_DIR/etc/fstab" << 'EOF'
# <file system> <mount point> <type> <options> <dump> <pass>
proc /proc proc defaults 0 0
sysfs /sys sysfs defaults 0 0
devtmpfs /dev devtmpfs defaults 0 0
tmpfs /tmp tmpfs defaults 0 0
EOF
# /etc/resolv.conf - DNS configuration (managed by Qt6 GUI)
cat > "$ROOTFS_DIR/etc/resolv.conf" << 'EOF'
# SparkOS DNS Configuration
# Managed by Qt6 GUI NetworkManager
# Fallback to public DNS servers
nameserver 8.8.8.8
nameserver 8.8.4.4
nameserver 1.1.1.1
nameserver 1.0.0.1
EOF
# Create README
cat > "$ROOTFS_DIR/README.txt" << 'EOF'
SparkOS Root Filesystem
=======================
This is the root filesystem for SparkOS, a GUI-only Linux distribution.
SparkOS Philosophy:
- GUI-Only: No CLI tools, no shell, no Unix utilities
- Network-First: Networking integrated into Qt6 GUI
- Direct Kernel Interface: Qt6 communicates directly with Linux kernel
- No Unix Baggage: No users, groups, passwords, or authentication
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:
/sbin - Init binary only
/etc - Minimal configuration files
/proc, /sys, /dev - Kernel interfaces
/tmp - Temporary files
/usr - Qt6 GUI application and libraries
/var - Variable data (overlay mount)
/root - Root home directory
Network Configuration:
- Managed entirely through Qt6 GUI
- Init brings up interfaces via direct ioctl calls
- DHCP and network management handled by Qt6 NetworkManager
- /etc/resolv.conf provides fallback DNS servers
Boot Process:
1. Linux kernel loads
2. Init (PID 1) mounts filesystems
3. Init brings up network interfaces
4. Init spawns Qt6 GUI application
5. All user interaction through GUI
Note: This is a minimal, GUI-only system.
No shell, no CLI tools, no busybox.
All functionality is provided through the Qt6 GUI application.
EOF
echo ""
echo "Root filesystem structure created at: $ROOTFS_DIR"
echo ""
echo "SparkOS Configuration:"
echo " - Architecture: GUI-only, no CLI"
echo " - Init: Self-contained, no external dependencies"
echo " - Network: Direct C implementation via ioctl"
echo " - User Experience: Pure Qt6 GUI"
echo ""
echo "Next steps:"
echo " 1. Build init: make init"
echo " 2. Install init: make install"
echo " 3. Build Qt6 GUI: make gui"
echo " 4. Create bootable image: sudo make image"
echo ""
echo "Philosophy:"
echo " No busybox, no shell, no CLI tools"
echo " Everything is GUI-driven through Qt6"

45
sparkos/scripts/test.sh Normal file
View File

@@ -0,0 +1,45 @@
#!/bin/sh
echo "SparkOS Docker Test Environment"
echo "================================"
echo ""
echo "Verifying SparkOS init binary..."
echo "--------------------------------"
if [ -f /sparkos/rootfs/sbin/init ]; then
echo "✓ Init binary exists"
ls -lh /sparkos/rootfs/sbin/init
echo ""
echo "File type:"
if command -v file >/dev/null 2>&1; then
file /sparkos/rootfs/sbin/init
else
echo " (file command not available)"
fi
echo ""
echo "Dependencies:"
ldd /sparkos/rootfs/sbin/init 2>&1 || echo " Static binary (no dependencies)"
else
echo "✗ Init binary not found!"
exit 1
fi
echo ""
echo "Root filesystem structure:"
echo "--------------------------"
ls -la /sparkos/rootfs/
echo ""
echo "================================"
echo "✓ SparkOS is ready for testing!"
echo "================================"
echo ""
echo "Summary:"
echo " - Init: Custom SparkOS init system (no external dependencies)"
echo " - Architecture: GUI-only, no CLI/shell"
echo " - Network: Direct C implementation via ioctl"
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 "To test the init system:"
echo " docker run --rm <image> /sparkos/rootfs/sbin/init"

261
sparkos/src/init.c Normal file
View File

@@ -0,0 +1,261 @@
/*
* SparkOS Init - Minimal init system for SparkOS
* 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 <stdlib.h>
#include <unistd.h>
#include <sys/wait.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 <errno.h>
#include <string.h>
#include <arpa/inet.h>
#include <limits.h>
static void signal_handler(int sig) {
if (sig == SIGCHLD) {
// Reap zombie processes
while (waitpid(-1, NULL, WNOHANG) > 0);
}
}
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=/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);
}
/*
* 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;
// Create socket for ioctl operations
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0) {
perror("socket creation failed");
return -1;
}
// Prepare interface request structure
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, ifname, IFNAMSIZ - 1);
ifr.ifr_name[IFNAMSIZ - 1] = '\0'; // Ensure null termination
// Get current flags
if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) {
close(sock);
return -1; // Interface doesn't exist
}
// Bring interface up
ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
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[PATH_MAX];
char *p = NULL;
size_t len;
len = strlen(path);
if (len >= PATH_MAX) {
errno = ENAMETOOLONG;
return -1;
}
snprintf(tmp, sizeof(tmp), "%s", path);
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[]) {
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
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 using direct system calls
printf("Mounting essential filesystems...\n");
if (mount_fs("proc", "/proc", "proc", 0) != 0) {
fprintf(stderr, "Warning: Failed to mount /proc\n");
}
if (mount_fs("sysfs", "/sys", "sysfs", 0) != 0) {
fprintf(stderr, "Warning: Failed to mount /sys\n");
}
if (mount_fs("devtmpfs", "/dev", "devtmpfs", 0) != 0) {
fprintf(stderr, "Warning: Failed to mount /dev\n");
}
if (mount_fs("tmpfs", "/tmp", "tmpfs", 0) != 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 (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");
}
// Mount overlay on /var for logs and runtime data
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");
} else {
printf("Overlay filesystem mounted on /var (base OS is immutable)\n");
}
// Mount tmpfs on /run for runtime data
if (mkdir_p("/run") == 0) {
if (mount_fs("tmpfs", "/run", "tmpfs", 0) != 0) {
fprintf(stderr, "Warning: Failed to mount /run\n");
}
}
// Initialize network interfaces
init_network();
printf("\nStarting Qt6 GUI application...\n");
printf("Welcome to SparkOS!\n");
printf("===================\n");
printf("Base OS: Read-only (immutable)\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");
printf("No CLI/Shell - Pure GUI Experience\n\n");
// Main loop - keep respawning GUI application
while (1) {
spawn_gui();
// If GUI exits, respawn after a short delay
printf("\nGUI application exited. Restarting in 2 seconds...\n");
sleep(2);
}
return 0;
}

View File

@@ -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
)

View File

@@ -0,0 +1,188 @@
/*
* SparkOS Qt6 GUI Application
* Direct kernel interface - bypassing Unix conventions
* Network-first, GUI-only operating system
*/
#include <QApplication>
#include <QWidget>
#include <QLabel>
#include <QVBoxLayout>
#include <QPushButton>
#include <QFont>
#include <QScreen>
#include <QStyle>
#include <QProcess>
#include <QTextEdit>
#include <QFile>
#include <QIODevice>
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"