mirror of
https://github.com/johndoe6345789/metabuilder.git
synced 2026-04-24 13:54:57 +00:00
feat: Add SparkOS
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
49
sparkos/.dockerignore
Normal file
49
sparkos/.dockerignore
Normal 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
|
||||
267
sparkos/.github/workflows/build-image.yml
vendored
Normal file
267
sparkos/.github/workflows/build-image.yml
vendored
Normal 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
|
||||
115
sparkos/.github/workflows/docker-publish.yml
vendored
Normal file
115
sparkos/.github/workflows/docker-publish.yml
vendored
Normal 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
169
sparkos/.github/workflows/release.yml
vendored
Normal 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
74
sparkos/.gitignore
vendored
Normal 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
153
sparkos/ARCHITECTURE.md
Normal 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
76
sparkos/CONTRIBUTING.md
Normal 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
48
sparkos/Dockerfile
Normal 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
36
sparkos/Dockerfile.image
Normal 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
|
||||
111
sparkos/INIT_VERIFICATION.md
Normal file
111
sparkos/INIT_VERIFICATION.md
Normal 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
21
sparkos/LICENSE
Normal 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
77
sparkos/Makefile
Normal 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
482
sparkos/README.md
Normal 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
233
sparkos/RELEASING.md
Normal 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
|
||||
59
sparkos/config/RELEASE_README.md
Normal file
59
sparkos/config/RELEASE_README.md
Normal 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
30
sparkos/config/build.conf
Normal 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
|
||||
36
sparkos/config/grub-embedded.cfg.in
Normal file
36
sparkos/config/grub-embedded.cfg.in
Normal 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
|
||||
42
sparkos/config/grub.cfg.in
Normal file
42
sparkos/config/grub.cfg.in
Normal 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
|
||||
}
|
||||
23
sparkos/config/image-readme.txt
Normal file
23
sparkos/config/image-readme.txt
Normal 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
|
||||
74
sparkos/config/image-release-readme.txt
Normal file
74
sparkos/config/image-release-readme.txt
Normal 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
|
||||
11
sparkos/docker-compose.yml
Normal file
11
sparkos/docker-compose.yml
Normal 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
41
sparkos/rootfs/README.txt
Normal 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
5
sparkos/rootfs/etc/fstab
Normal 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
|
||||
1
sparkos/rootfs/etc/hostname
Normal file
1
sparkos/rootfs/etc/hostname
Normal file
@@ -0,0 +1 @@
|
||||
sparkos
|
||||
3
sparkos/rootfs/etc/hosts
Normal file
3
sparkos/rootfs/etc/hosts
Normal file
@@ -0,0 +1,3 @@
|
||||
127.0.0.1 localhost
|
||||
127.0.1.1 sparkos
|
||||
::1 localhost ip6-localhost ip6-loopback
|
||||
10
sparkos/rootfs/etc/network/interfaces
Normal file
10
sparkos/rootfs/etc/network/interfaces
Normal 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
|
||||
17
sparkos/rootfs/etc/profile
Normal file
17
sparkos/rootfs/etc/profile
Normal 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 ""
|
||||
6
sparkos/rootfs/etc/resolv.conf
Normal file
6
sparkos/rootfs/etc/resolv.conf
Normal 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
|
||||
12
sparkos/rootfs/home/spark/.profile
Normal file
12
sparkos/rootfs/home/spark/.profile
Normal 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
|
||||
50
sparkos/rootfs/home/spark/clone-sparkos.sh
Executable file
50
sparkos/rootfs/home/spark/clone-sparkos.sh
Executable 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
|
||||
12
sparkos/rootfs/root/.profile
Normal file
12
sparkos/rootfs/root/.profile
Normal 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
67
sparkos/scripts/build-image.sh
Executable 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
37
sparkos/scripts/build.sh
Executable 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
132
sparkos/scripts/create_image.sh
Executable 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!"
|
||||
148
sparkos/scripts/docker-image-create-uefi-old.sh
Executable file
148
sparkos/scripts/docker-image-create-uefi-old.sh
Executable 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"
|
||||
129
sparkos/scripts/docker-image-create-uefi.sh
Executable file
129
sparkos/scripts/docker-image-create-uefi.sh
Executable 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"
|
||||
71
sparkos/scripts/docker-image-download-kernel.sh
Executable file
71
sparkos/scripts/docker-image-download-kernel.sh
Executable 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
|
||||
29
sparkos/scripts/docker-image-install-tools.sh
Executable file
29
sparkos/scripts/docker-image-install-tools.sh
Executable 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/*
|
||||
6
sparkos/scripts/docker-install-packages.sh
Executable file
6
sparkos/scripts/docker-install-packages.sh
Executable 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
183
sparkos/scripts/docker-release.sh
Executable 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"
|
||||
19
sparkos/scripts/docker-setup-config.sh
Executable file
19
sparkos/scripts/docker-setup-config.sh
Executable 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
|
||||
25
sparkos/scripts/docker-setup-rootfs.sh
Executable file
25
sparkos/scripts/docker-setup-rootfs.sh
Executable 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
228
sparkos/scripts/install.sh
Executable 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
120
sparkos/scripts/setup_rootfs.sh
Executable 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
45
sparkos/scripts/test.sh
Normal 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
261
sparkos/src/init.c
Normal 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;
|
||||
}
|
||||
42
sparkos/src/qt6-app/CMakeLists.txt
Normal file
42
sparkos/src/qt6-app/CMakeLists.txt
Normal 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
|
||||
)
|
||||
188
sparkos/src/qt6-app/main.cpp
Normal file
188
sparkos/src/qt6-app/main.cpp
Normal 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"
|
||||
Reference in New Issue
Block a user