This commit is contained in:
2026-01-08 12:28:54 +00:00
commit d2a473c2bd
45 changed files with 3739 additions and 0 deletions

View File

@@ -0,0 +1,75 @@
#cloud-config
autoinstall:
version: 1
# Locale and keyboard
locale: en_US.UTF-8
keyboard:
layout: us
# Network configuration - DHCP on all interfaces
network:
network:
version: 2
ethernets:
id0:
match:
driver: "*"
dhcp4: true
# Storage - use entire disk
storage:
layout:
name: direct
# Identity - create ecouser
identity:
hostname: ecoos
username: ecouser
# Password: ecouser (hashed with mkpasswd -m sha-512)
password: "$6$rounds=4096$randomsalt$n8Y5TqMKJZ5kM3LN0Y5fZ5Y5kM3LN0Y5fZ5Y5kM3LN0Y5fZ5Y5kM3LN0Y5fZ5Y5kM3LN0Y5fZ5Y5kM3LN0Y5f"
# SSH
ssh:
install-server: true
allow-pw: true
# Additional packages
packages:
- sway
- seatd
- pipewire
- pipewire-pulse
- foot
- curl
- git
- htop
# Late commands - run after installation
late-commands:
# Add ecouser to required groups
- curtin in-target -- usermod -aG sudo,video,render,input,seat ecouser
# Enable passwordless sudo for ecouser
- echo "ecouser ALL=(ALL) NOPASSWD:ALL" > /target/etc/sudoers.d/ecouser
- chmod 440 /target/etc/sudoers.d/ecouser
# Enable seatd
- curtin in-target -- systemctl enable seatd
# Install Deno
- curtin in-target -- curl -fsSL https://deno.land/install.sh | DENO_INSTALL=/opt/eco sh
# Copy eco-daemon files (assumes they're on the ISO)
- cp -r /cdrom/eco/* /target/opt/eco/
# Enable eco-daemon service
- curtin in-target -- systemctl enable eco-daemon
# Install Google Chrome
- curtin in-target -- wget -q -O /tmp/chrome.deb https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
- curtin in-target -- apt-get install -y /tmp/chrome.deb
- curtin in-target -- rm /tmp/chrome.deb
# Reboot after installation
shutdown: reboot

View File

@@ -0,0 +1,27 @@
#!/bin/sh
# Create ecouser for running Sway and Chrome
set -e
echo "Creating ecouser..."
# Create ecouser with home directory and GECOS field (prevents "I have no name!" in terminal)
useradd -m -s /bin/bash -c "EcoOS User" ecouser || true
# Add ecouser to necessary groups:
# video,render - GPU access
# audio - audio access
# input - input devices
# seat - seatd compositor access
# sudo - sudo privileges
# adm,cdrom,plugdev - standard Ubuntu groups
usermod -aG video,render,audio,input,seat,sudo,adm,cdrom,plugdev ecouser || true
# Set a default password (ecouser:ecouser)
echo "ecouser:ecouser" | chpasswd
# Enable sudo without password for ecouser
echo "ecouser ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/ecouser
chmod 440 /etc/sudoers.d/ecouser
echo "ecouser created."

View File

@@ -0,0 +1,14 @@
#!/bin/sh
# Fix NetworkManager connection file permissions
set -e
echo "Fixing NetworkManager connection permissions..."
# NetworkManager requires connection files to be owned by root:root with 600 permissions
if [ -d /etc/NetworkManager/system-connections ]; then
chown -R root:root /etc/NetworkManager/system-connections
chmod 600 /etc/NetworkManager/system-connections/*.nmconnection 2>/dev/null || true
fi
echo "NetworkManager permissions fixed."

View File

@@ -0,0 +1,19 @@
#!/bin/sh
# Install Chromium browser (from Ubuntu repos - more reliable than downloading Chrome)
set -e
echo "Installing Chromium browser..."
# Install Chromium from Ubuntu repos
apt-get update
apt-get install -y chromium-browser
# Create symlink so scripts expecting google-chrome-stable work
ln -sf /usr/bin/chromium-browser /usr/bin/google-chrome-stable
# Clean up
apt-get clean
rm -rf /var/lib/apt/lists/*
echo "Chromium browser installed."

View File

@@ -0,0 +1,29 @@
#!/bin/sh
# Enable EcoOS services
set -e
echo "Enabling systemd-networkd for static IP..."
systemctl enable systemd-networkd.service
systemctl enable systemd-networkd-wait-online.service
echo "Disabling NetworkManager (using networkd instead)..."
systemctl disable NetworkManager.service 2>/dev/null || true
systemctl mask NetworkManager.service 2>/dev/null || true
echo "Enabling seatd service..."
systemctl enable seatd.service
echo "Enabling eco-daemon service..."
systemctl enable eco-daemon.service
echo "Enabling installer service..."
systemctl enable ecoos-installer.service
echo "Enabling SSH service..."
systemctl enable ssh.service || true
echo "Enabling debug service..."
systemctl enable debug-network.service || true
echo "Services enabled."

View File

@@ -0,0 +1,52 @@
#!/bin/sh
# Final permissions fix before squashfs creation
# Ensures /etc and critical directories have correct permissions
# This is CRITICAL - wrong permissions break login, networking, and services
set -e
echo "Fixing critical directory permissions..."
# /etc must be world-readable for systemd and other services to work
chmod 755 /etc
# Fix all subdirectories in /etc that need to be readable
for dir in /etc/systemd /etc/systemd/system /etc/systemd/network \
/etc/default /etc/security /etc/pam.d /etc/skel \
/etc/profile.d /etc/sudoers.d /etc/bash_completion.d \
/etc/apt /etc/dpkg /etc/ssl /etc/ssh /etc/sway; do
if [ -d "$dir" ]; then
chmod 755 "$dir"
fi
done
# Critical files that must be world-readable for system to function
# These are essential for user/group lookups and shell login
for file in /etc/passwd /etc/group /etc/hosts /etc/hostname \
/etc/profile /etc/bash.bashrc /etc/environment \
/etc/shells /etc/nsswitch.conf /etc/resolv.conf \
/etc/machine-id /etc/ld.so.conf; do
if [ -f "$file" ]; then
chmod 644 "$file"
fi
done
# Shadow files should be root-only readable
chmod 640 /etc/shadow 2>/dev/null || true
chmod 640 /etc/gshadow 2>/dev/null || true
# Sudoers files need specific permissions
chmod 440 /etc/sudoers 2>/dev/null || true
if [ -d /etc/sudoers.d ]; then
find /etc/sudoers.d -type f -exec chmod 440 {} \;
fi
# Fix network config file permissions
if [ -f /etc/systemd/network/10-wired.network ]; then
chmod 644 /etc/systemd/network/10-wired.network
fi
# Recursively fix /etc - directories should be 755, files 644 (except special cases)
find /etc -type d -exec chmod 755 {} \; 2>/dev/null || true
echo "Permissions fixed."

View File

@@ -0,0 +1,17 @@
[connection]
id=Wired connection
uuid=2b8f4e84-9c7d-4b3e-8f2a-1d5e6f7a8b9c
type=ethernet
autoconnect=true
autoconnect-priority=100
[ethernet]
[ipv4]
method=manual
addresses=10.0.2.15/24
gateway=10.0.2.2
dns=10.0.2.3;
[ipv6]
method=ignore

View File

@@ -0,0 +1,5 @@
[Match]
Name=ens* enp* eth*
[Network]
DHCP=yes

View File

@@ -0,0 +1,12 @@
[Unit]
Description=Debug Network Info to Serial
After=network-online.target eco-daemon.service
Wants=network-online.target
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/bin/bash -c 'echo "=== NETWORK DEBUG ===" > /dev/ttyS0; ip addr >> /dev/ttyS0; echo "=== ROUTES ===" >> /dev/ttyS0; ip route >> /dev/ttyS0; echo "=== LISTENING ===" >> /dev/ttyS0; ss -tlnp >> /dev/ttyS0; echo "=== NM STATUS ===" >> /dev/ttyS0; nmcli device status >> /dev/ttyS0 2>&1; nmcli connection show >> /dev/ttyS0 2>&1; echo "=== END DEBUG ===" >> /dev/ttyS0'
[Install]
WantedBy=multi-user.target

View File

@@ -0,0 +1,24 @@
[Unit]
Description=EcoOS Daemon
After=network-online.target seatd.service systemd-networkd-wait-online.service
Wants=seatd.service network-online.target
Requires=seatd.service
StartLimitIntervalSec=0
[Service]
Type=simple
ExecStart=/opt/eco/bin/eco-daemon
Restart=always
RestartSec=5
WorkingDirectory=/opt/eco
# Give daemon enough capabilities
AmbientCapabilities=CAP_NET_BIND_SERVICE CAP_SYS_ADMIN
# Logging
StandardOutput=journal
StandardError=journal
SyslogIdentifier=eco-daemon
[Install]
WantedBy=multi-user.target

View File

@@ -0,0 +1,18 @@
[Unit]
Description=EcoOS Installer
After=multi-user.target getty@tty1.service
ConditionKernelCommandLine=ecoos_install=1
Conflicts=getty@tty1.service
[Service]
Type=oneshot
ExecStart=/opt/eco/installer/install.sh
StandardInput=tty
StandardOutput=tty
StandardError=tty
TTYPath=/dev/tty1
TTYReset=yes
TTYVHangup=yes
[Install]
WantedBy=multi-user.target

View File

@@ -0,0 +1 @@
/etc/systemd/system/ecoos-installer.service

Binary file not shown.

View File

@@ -0,0 +1,22 @@
#!/bin/bash
# Debug network info - outputs to serial console
exec > /dev/ttyS0 2>&1
echo "=== NETWORK DEBUG ==="
echo "Date: $(date)"
echo ""
echo "=== IP ADDRESSES ==="
ip addr
echo ""
echo "=== ROUTES ==="
ip route
echo ""
echo "=== NETWORKMANAGER CONNECTIONS ==="
nmcli connection show
echo ""
echo "=== NETWORKMANAGER DEVICES ==="
nmcli device status
echo ""
echo "=== LISTENING PORTS ==="
ss -tlnp
echo "=== END DEBUG ==="

View File

@@ -0,0 +1,545 @@
#!/bin/bash
#
# EcoOS Installer
# Installs EcoOS from live USB to disk
#
set -e
# Configuration
TIMEOUT=10
HOSTNAME="ecoos"
USERNAME="ecouser"
SQUASHFS_PATH="/run/live/medium/live/filesystem.squashfs"
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
log() {
echo -e "${GREEN}[EcoOS]${NC} $1" >&2
}
warn() {
echo -e "${YELLOW}[WARNING]${NC} $1" >&2
}
error() {
echo -e "${RED}[ERROR]${NC} $1" >&2
exit 1
}
# Get the device the live system is running from
get_live_device() {
local live_dev=""
# Find the device backing /run/live/medium
if mountpoint -q /run/live/medium 2>/dev/null; then
live_dev=$(findmnt -n -o SOURCE /run/live/medium | sed 's/[0-9]*$//')
fi
# Also check /cdrom for older casper
if [ -z "$live_dev" ] && mountpoint -q /cdrom 2>/dev/null; then
live_dev=$(findmnt -n -o SOURCE /cdrom | sed 's/[0-9]*$//')
fi
echo "$live_dev"
}
# List available disks (excluding live media and loop devices)
list_disks() {
local live_dev=$(get_live_device)
local disks=()
for disk in /sys/block/sd* /sys/block/nvme* /sys/block/vd*; do
[ -e "$disk" ] || continue
local name=$(basename "$disk")
local dev="/dev/$name"
# Skip if this is the live media
if [ "$dev" = "$live_dev" ]; then
continue
fi
# Skip removable devices (USB sticks) - but allow if it's the only option
local removable=$(cat "$disk/removable" 2>/dev/null || echo "0")
# Get size in GB
local size_bytes=$(cat "$disk/size" 2>/dev/null || echo "0")
local size_gb=$((size_bytes * 512 / 1024 / 1024 / 1024))
# Skip disks smaller than 10GB
if [ "$size_gb" -lt 10 ]; then
continue
fi
# Get model
local model=$(cat "$disk/device/model" 2>/dev/null | tr -d '\n' || echo "Unknown")
disks+=("$dev|$size_gb|$model|$removable")
done
printf '%s\n' "${disks[@]}"
}
# Select disk with timeout
# All UI output goes to stderr so stdout only returns the device path
select_disk() {
local disks
mapfile -t disks < <(list_disks)
if [ ${#disks[@]} -eq 0 ]; then
error "No suitable disks found for installation"
fi
echo "" >&2
echo -e "${BLUE}╔════════════════════════════════════════════════════════════╗${NC}" >&2
echo -e "${BLUE}${NC} ${GREEN}EcoOS Disk Installation${NC} ${BLUE}${NC}" >&2
echo -e "${BLUE}╚════════════════════════════════════════════════════════════╝${NC}" >&2
echo "" >&2
echo "Available disks:" >&2
echo "" >&2
local i=1
local default_disk=""
local default_idx=1
local max_size=0
for disk_info in "${disks[@]}"; do
IFS='|' read -r dev size model removable <<< "$disk_info"
local marker=""
if [ "$size" -gt "$max_size" ]; then
max_size=$size
default_disk=$dev
default_idx=$i
fi
printf " ${YELLOW}%d)${NC} %-12s %4d GB %s\n" "$i" "$dev" "$size" "$model" >&2
((i++))
done
echo "" >&2
echo -e "Default: ${GREEN}$default_disk${NC} (largest disk)" >&2
echo "" >&2
echo -e "${YELLOW}WARNING: Selected disk will be COMPLETELY ERASED!${NC}" >&2
echo "" >&2
# Countdown with input check
local selected=""
local remaining=$TIMEOUT
while [ $remaining -gt 0 ]; do
printf "\rSelect disk [1-%d] or press Enter for default (%ds remaining): " "${#disks[@]}" "$remaining" >&2
if read -t 1 -n 1 input; then
if [ -z "$input" ]; then
# Enter pressed - use default
selected=$default_idx
break
elif [[ "$input" =~ ^[0-9]$ ]] && [ "$input" -ge 1 ] && [ "$input" -le ${#disks[@]} ]; then
selected=$input
echo "" >&2
break
else
echo "" >&2
warn "Invalid selection. Please enter 1-${#disks[@]}"
remaining=$TIMEOUT
fi
fi
((remaining--))
done
if [ -z "$selected" ]; then
selected=$default_idx
echo "" >&2
log "Timeout - auto-selecting default disk"
fi
# Get selected disk
local idx=$((selected - 1))
IFS='|' read -r TARGET_DISK size model removable <<< "${disks[$idx]}"
echo "" >&2
log "Selected: $TARGET_DISK ($size GB - $model)"
echo "" >&2
# Final confirmation with shorter timeout
echo -e "${RED}╔════════════════════════════════════════════════════════════╗${NC}" >&2
echo -e "${RED}║ ALL DATA ON $TARGET_DISK WILL BE PERMANENTLY DESTROYED! ║${NC}" >&2
echo -e "${RED}╚════════════════════════════════════════════════════════════╝${NC}" >&2
echo "" >&2
local confirm_timeout=10
printf "Press 'y' to confirm, any other key to cancel (%ds): " "$confirm_timeout" >&2
if read -t $confirm_timeout -n 1 confirm; then
echo "" >&2
if [ "$confirm" != "y" ] && [ "$confirm" != "Y" ]; then
error "Installation cancelled by user"
fi
else
echo "" >&2
log "Auto-confirming installation..."
fi
# Only this goes to stdout - the actual device path
echo "$TARGET_DISK"
}
# Partition the disk
partition_disk() {
local disk=$1
log "Partitioning $disk..."
# Wipe existing partition table
wipefs -a "$disk" >/dev/null 2>&1 || true
# Create GPT partition table
parted -s "$disk" mklabel gpt
# Create EFI partition (512MB)
parted -s "$disk" mkpart ESP fat32 1MiB 513MiB
parted -s "$disk" set 1 esp on
# Create root partition (rest of disk)
parted -s "$disk" mkpart root ext4 513MiB 100%
# Wait for partitions to appear
sleep 2
partprobe "$disk"
sleep 1
# Determine partition names (nvme vs sd)
if [[ "$disk" == *"nvme"* ]]; then
EFI_PART="${disk}p1"
ROOT_PART="${disk}p2"
else
EFI_PART="${disk}1"
ROOT_PART="${disk}2"
fi
log "Created partitions: EFI=$EFI_PART, Root=$ROOT_PART"
}
# Format partitions
format_partitions() {
log "Formatting partitions..."
mkfs.fat -F 32 -n "EFI" "$EFI_PART"
mkfs.ext4 -F -L "EcoOS" "$ROOT_PART"
log "Partitions formatted"
}
# Mount partitions
mount_partitions() {
log "Mounting partitions..."
mkdir -p /mnt/target
mount "$ROOT_PART" /mnt/target
mkdir -p /mnt/target/boot/efi
mount "$EFI_PART" /mnt/target/boot/efi
log "Partitions mounted at /mnt/target"
}
# Copy system files
copy_system() {
log "Copying system files (this may take several minutes)..."
# Check if squashfs exists
if [ ! -f "$SQUASHFS_PATH" ]; then
# Try alternative paths (including casper paths for Ubuntu)
for path in /run/live/medium/live/filesystem.squashfs \
/cdrom/casper/filesystem.squashfs \
/cdrom/live/filesystem.squashfs \
/isodevice/casper/filesystem.squashfs \
/lib/live/mount/medium/live/filesystem.squashfs \
/rofs/../casper/filesystem.squashfs; do
if [ -f "$path" ]; then
SQUASHFS_PATH="$path"
break
fi
done
fi
# If still not found, try to find it
if [ ! -f "$SQUASHFS_PATH" ]; then
local found=$(find /cdrom /run /media -name "filesystem.squashfs" 2>/dev/null | head -1)
if [ -n "$found" ]; then
SQUASHFS_PATH="$found"
fi
fi
if [ ! -f "$SQUASHFS_PATH" ]; then
error "Cannot find filesystem.squashfs"
fi
log "Extracting from $SQUASHFS_PATH..."
# Extract squashfs
unsquashfs -f -d /mnt/target "$SQUASHFS_PATH"
log "System files copied"
}
# Configure the installed system
configure_system() {
log "Configuring system..."
# Get UUIDs
local root_uuid=$(blkid -s UUID -o value "$ROOT_PART")
local efi_uuid=$(blkid -s UUID -o value "$EFI_PART")
# Create fstab
cat > /mnt/target/etc/fstab << EOF
# EcoOS fstab
UUID=$root_uuid / ext4 defaults,noatime 0 1
UUID=$efi_uuid /boot/efi vfat umask=0077 0 1
EOF
# Set hostname
echo "$HOSTNAME" > /mnt/target/etc/hostname
cat > /mnt/target/etc/hosts << EOF
127.0.0.1 localhost
127.0.1.1 $HOSTNAME
::1 localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
EOF
# Ensure seat group exists (for seatd)
if ! grep -q "^seat:" /mnt/target/etc/group; then
chroot /mnt/target groupadd seat 2>/dev/null || true
fi
# Ensure render group exists (for GPU access)
if ! grep -q "^render:" /mnt/target/etc/group; then
chroot /mnt/target groupadd render 2>/dev/null || true
fi
# Ensure ecouser exists and is configured
# Groups: video,render (GPU), audio, input (devices), sudo, seat (seatd)
if ! grep -q "^$USERNAME:" /mnt/target/etc/passwd; then
chroot /mnt/target useradd -m -s /bin/bash -c "EcoOS User" -G video,render,audio,input,sudo,adm,cdrom,plugdev,seat "$USERNAME"
else
# Add to required groups if user already exists
chroot /mnt/target usermod -a -G video,render,seat "$USERNAME" 2>/dev/null || true
# Set the GECOS/full name field if missing
chroot /mnt/target chfn -f "EcoOS User" "$USERNAME" 2>/dev/null || true
fi
# Create Sway config directory for ecouser
mkdir -p /mnt/target/home/$USERNAME/.config/sway
if [ -f /mnt/target/etc/sway/config ]; then
cp /mnt/target/etc/sway/config /mnt/target/home/$USERNAME/.config/sway/config
fi
chroot /mnt/target chown -R $USERNAME:$USERNAME /home/$USERNAME/.config 2>/dev/null || true
# Set a default password (ecouser:ecouser) - should be changed on first boot
echo "$USERNAME:ecouser" | chroot /mnt/target chpasswd
# Enable sudo for ecouser
echo "$USERNAME ALL=(ALL) NOPASSWD:ALL" > /mnt/target/etc/sudoers.d/ecouser
chmod 440 /mnt/target/etc/sudoers.d/ecouser
# Remove live-boot packages marker if present
rm -f /mnt/target/etc/live 2>/dev/null || true
# Enable systemd-networkd for static IP (more reliable than NetworkManager)
chroot /mnt/target systemctl enable systemd-networkd.service 2>/dev/null || true
chroot /mnt/target systemctl enable systemd-networkd-wait-online.service 2>/dev/null || true
# Disable NetworkManager to avoid conflicts
chroot /mnt/target systemctl disable NetworkManager.service 2>/dev/null || true
chroot /mnt/target systemctl mask NetworkManager.service 2>/dev/null || true
# Create network config for systemd-networkd (DHCP for QEMU/VMs)
mkdir -p /mnt/target/etc/systemd/network
cat > /mnt/target/etc/systemd/network/10-wired.network << 'NETEOF'
[Match]
Name=ens* enp* eth*
[Network]
DHCP=yes
NETEOF
# Fix critical directory permissions - /etc must be world-readable
# for systemd-networkd and other services to read their config files
# This is CRITICAL - squashfs may have wrong permissions from Docker build
log "Fixing /etc permissions..."
# Fix /etc and all subdirectories recursively
find /mnt/target/etc -type d -exec chmod 755 {} \;
# Fix critical files that must be world-readable
for file in passwd group hosts hostname profile bash.bashrc environment \
shells nsswitch.conf resolv.conf machine-id ld.so.conf; do
if [ -f "/mnt/target/etc/$file" ]; then
chmod 644 "/mnt/target/etc/$file"
fi
done
# Shadow files should be root-only readable
chmod 640 /mnt/target/etc/shadow 2>/dev/null || true
chmod 640 /mnt/target/etc/gshadow 2>/dev/null || true
# Sudoers files need specific permissions
chmod 440 /mnt/target/etc/sudoers 2>/dev/null || true
find /mnt/target/etc/sudoers.d -type f -exec chmod 440 {} \; 2>/dev/null || true
# Network config
chmod 644 /mnt/target/etc/systemd/network/10-wired.network
log "systemd-networkd enabled for networking"
# Enable other services for installed system
chroot /mnt/target systemctl enable eco-daemon.service 2>/dev/null || true
chroot /mnt/target systemctl enable seatd.service 2>/dev/null || true
chroot /mnt/target systemctl enable ssh.service 2>/dev/null || true
chroot /mnt/target systemctl enable debug-network.service 2>/dev/null || true
log "System configured"
}
# Install bootloader
install_bootloader() {
log "Installing GRUB bootloader..."
# Mount necessary filesystems for chroot
mount --bind /dev /mnt/target/dev
mount --bind /dev/pts /mnt/target/dev/pts
mount --bind /proc /mnt/target/proc
mount --bind /sys /mnt/target/sys
mount --bind /run /mnt/target/run
# Fix GRUB default config - remove casper/live boot parameters and add serial console
if [ -f /mnt/target/etc/default/grub ]; then
# Remove any boot=casper or live-related parameters
sed -i 's/boot=casper//g' /mnt/target/etc/default/grub
# Update GRUB_CMDLINE_LINUX_DEFAULT with serial console for debugging
sed -i 's/^GRUB_CMDLINE_LINUX_DEFAULT=.*/GRUB_CMDLINE_LINUX_DEFAULT="console=tty1 console=ttyS0,115200n8"/' /mnt/target/etc/default/grub
# If line doesn't exist, add it
if ! grep -q "GRUB_CMDLINE_LINUX_DEFAULT" /mnt/target/etc/default/grub; then
echo 'GRUB_CMDLINE_LINUX_DEFAULT="console=tty1 console=ttyS0,115200n8"' >> /mnt/target/etc/default/grub
fi
# Enable serial terminal in GRUB
echo 'GRUB_TERMINAL="console serial"' >> /mnt/target/etc/default/grub
echo 'GRUB_SERIAL_COMMAND="serial --speed=115200 --unit=0 --word=8 --parity=no --stop=1"' >> /mnt/target/etc/default/grub
fi
# Disable casper-related services
log "Disabling live boot services..."
chroot /mnt/target systemctl disable casper.service 2>/dev/null || true
chroot /mnt/target systemctl disable casper-md5check.service 2>/dev/null || true
chroot /mnt/target systemctl mask casper.service 2>/dev/null || true
chroot /mnt/target systemctl mask casper-md5check.service 2>/dev/null || true
# Remove casper initramfs hooks to prevent live-boot behavior
log "Removing casper initramfs hooks..."
rm -rf /mnt/target/usr/share/initramfs-tools/scripts/casper 2>/dev/null || true
rm -rf /mnt/target/usr/share/initramfs-tools/scripts/casper-premount 2>/dev/null || true
rm -rf /mnt/target/usr/share/initramfs-tools/scripts/casper-bottom 2>/dev/null || true
rm -f /mnt/target/usr/share/initramfs-tools/hooks/casper 2>/dev/null || true
rm -f /mnt/target/etc/initramfs-tools/conf.d/casper.conf 2>/dev/null || true
# Regenerate initramfs without casper hooks
log "Regenerating initramfs..."
chroot /mnt/target update-initramfs -u -k all
# Ensure proper boot target
chroot /mnt/target systemctl set-default multi-user.target 2>/dev/null || true
# Install GRUB
chroot /mnt/target grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=EcoOS --recheck
# Generate GRUB config
chroot /mnt/target update-grub
# Cleanup mounts (use lazy unmount for stubborn mounts, reverse order)
sync
umount -l /mnt/target/run 2>/dev/null || true
umount -l /mnt/target/sys 2>/dev/null || true
umount -l /mnt/target/proc 2>/dev/null || true
umount -l /mnt/target/dev/pts 2>/dev/null || true
umount -l /mnt/target/dev 2>/dev/null || true
log "Bootloader installed"
}
# Cleanup and reboot
cleanup_and_reboot() {
log "Cleaning up..."
# Sync disks
sync
# Unmount
umount /mnt/target/boot/efi
umount /mnt/target
echo ""
echo -e "${GREEN}╔════════════════════════════════════════════════════════════╗${NC}"
echo -e "${GREEN}║ EcoOS Installation Complete! ║${NC}"
echo -e "${GREEN}╚════════════════════════════════════════════════════════════╝${NC}"
echo ""
echo "The system will reboot in 10 seconds..."
echo "Remove the USB drive when the screen goes blank."
echo ""
sleep 10
reboot
}
# Main installation flow
main() {
clear
echo ""
echo -e "${GREEN}"
echo " ███████╗ ██████╗ ██████╗ ██████╗ ███████╗"
echo " ██╔════╝██╔════╝██╔═══██╗██╔═══██╗██╔════╝"
echo " █████╗ ██║ ██║ ██║██║ ██║███████╗"
echo " ██╔══╝ ██║ ██║ ██║██║ ██║╚════██║"
echo " ███████╗╚██████╗╚██████╔╝╚██████╔╝███████║"
echo " ╚══════╝ ╚═════╝ ╚═════╝ ╚═════╝ ╚══════╝"
echo -e "${NC}"
echo " System Installer v1.0"
echo ""
# Check if running as root
if [ "$(id -u)" -ne 0 ]; then
error "This script must be run as root"
fi
# Select target disk
TARGET_DISK=$(select_disk)
# Partition disk
partition_disk "$TARGET_DISK"
# Format partitions
format_partitions
# Mount partitions
mount_partitions
# Copy system
copy_system
# Configure system
configure_system
# Install bootloader
install_bootloader
# Cleanup and reboot
cleanup_and_reboot
}
# Run main function
main "$@"

View File

@@ -0,0 +1,21 @@
#!/bin/sh
# EcoOS live-build configuration
# Note: EFI boot is handled manually in the Dockerfile build script
lb config noauto \
--architectures amd64 \
--distribution noble \
--archive-areas "main restricted universe multiverse" \
--binary-images iso-hybrid \
--bootappend-live "boot=casper quiet splash" \
--debian-installer false \
--memtest none \
--firmware-binary true \
--firmware-chroot true \
--updates true \
--security true \
--iso-application "EcoOS" \
--iso-publisher "EcoBridge" \
--iso-volume "EcoOS" \
"${@}"

View File

@@ -0,0 +1,57 @@
# EcoOS Base Packages
# System essentials
linux-image-generic
linux-headers-generic
systemd
dbus
network-manager
openssh-server
sudo
# EFI bootloader (required for UEFI boot)
grub-efi-amd64
grub-efi-amd64-signed
shim-signed
# Sway + Wayland
sway
swaybg
swaylock
swayidle
foot
wl-clipboard
xwayland
# Seat management
seatd
libseat1
# Tools
curl
wget
git
unzip
htop
vim
nano
tmux
jq
# System utilities
pciutils
usbutils
dmidecode
lshw
# Installer requirements
parted
squashfs-tools
dosfstools
e2fsprogs
# Live-build binary phase requirements (pre-install to avoid DNS issues)
mtools
syslinux
syslinux-common
isolinux
genisoimage

View File

@@ -0,0 +1,32 @@
# EcoOS Desktop Packages
# Audio
pipewire
pipewire-pulse
pipewire-alsa
wireplumber
libspa-0.2-bluetooth
# Fonts
fonts-noto
fonts-noto-color-emoji
fonts-liberation
fonts-dejavu
# Browser dependencies (Chrome installed via hook)
libnss3
libatk1.0-0
libatk-bridge2.0-0
libcups2
libdrm2
libxkbcommon0
libxcomposite1
libxdamage1
libxfixes3
libxrandr2
libgbm1
libasound2t64
# Utilities
grim
slurp

View File

@@ -0,0 +1,39 @@
# EcoOS Driver Packages
# GPU drivers - Mesa (open source)
xserver-xorg-video-all
mesa-utils
mesa-vulkan-drivers
libgl1-mesa-dri
libgbm1
libegl1
# Intel GPU
intel-media-va-driver
libva-drm2
libva2
# AMD GPU
libdrm-amdgpu1
# All firmware (Ubuntu combines into linux-firmware)
linux-firmware
# Storage
nvme-cli
smartmontools
mdadm
lvm2
cryptsetup
# USB/Input
libinput-tools
libinput-bin
# Bluetooth
bluez
bluez-tools
# Virtualization support
qemu-guest-agent
open-vm-tools

View File

@@ -0,0 +1,24 @@
[Unit]
Description=EcoOS Daemon
After=network-online.target seatd.service systemd-networkd-wait-online.service
Wants=seatd.service network-online.target
Requires=seatd.service
StartLimitIntervalSec=0
[Service]
Type=simple
ExecStart=/opt/eco/bin/eco-daemon
Restart=always
RestartSec=5
WorkingDirectory=/opt/eco
# Give daemon enough capabilities
AmbientCapabilities=CAP_NET_BIND_SERVICE CAP_SYS_ADMIN
# Logging
StandardOutput=journal
StandardError=journal
SyslogIdentifier=eco-daemon
[Install]
WantedBy=multi-user.target