cleaned up scripts to be more DRY
This commit is contained in:
parent
0e3a4c4dd5
commit
8032b83e6a
15 changed files with 1378 additions and 554 deletions
11
.github/workflows/release.yml
vendored
11
.github/workflows/release.yml
vendored
|
|
@ -50,16 +50,15 @@ jobs:
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Setup z/VM environment
|
- name: Setup z/VM environment
|
||||||
|
env:
|
||||||
|
ZVM_HOST: ${{ secrets.ZVM_HOST }}
|
||||||
|
ZVM_USER: ${{ secrets.ZVM_USER }}
|
||||||
|
ZVM_SSH_KEY: ${{ secrets.ZVM_SSH_KEY }}
|
||||||
run: |
|
run: |
|
||||||
# Load z/VM configuration from secret
|
|
||||||
echo "${{ secrets.ZVM_CONFIG }}" > .env.temp
|
|
||||||
source .env.temp
|
|
||||||
rm .env.temp
|
|
||||||
|
|
||||||
# Validate required variables
|
# Validate required variables
|
||||||
if [ -z "$ZVM_HOST" ] || [ -z "$ZVM_USER" ] || [ -z "$ZVM_SSH_KEY" ]; then
|
if [ -z "$ZVM_HOST" ] || [ -z "$ZVM_USER" ] || [ -z "$ZVM_SSH_KEY" ]; then
|
||||||
echo "Error: Missing required z/VM configuration"
|
echo "Error: Missing required z/VM configuration"
|
||||||
echo "ZVM_CONFIG secret must contain: ZVM_HOST, ZVM_USER, ZVM_SSH_KEY"
|
echo "Required secrets: ZVM_HOST, ZVM_USER, ZVM_SSH_KEY"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
|
||||||
8
.gitignore
vendored
8
.gitignore
vendored
|
|
@ -67,9 +67,8 @@ buildconfig
|
||||||
config
|
config
|
||||||
VERSION
|
VERSION
|
||||||
|
|
||||||
# Documentation
|
# Documentation WiP
|
||||||
CLAUDE.md
|
docs/*
|
||||||
PROJECT_SUMMARY.md
|
|
||||||
|
|
||||||
# Security
|
# Security
|
||||||
*.pem
|
*.pem
|
||||||
|
|
@ -78,6 +77,9 @@ PROJECT_SUMMARY.md
|
||||||
# Test artifacts
|
# Test artifacts
|
||||||
boot/rootfs-s390x.img
|
boot/rootfs-s390x.img
|
||||||
|
|
||||||
|
# Systemd documentation
|
||||||
|
docs/systemd-s390x-patches.md
|
||||||
|
|
||||||
# Build artifacts in boot directory (regenerated by make)
|
# Build artifacts in boot directory (regenerated by make)
|
||||||
boot/vmlinuz-linux
|
boot/vmlinuz-linux
|
||||||
boot/initramfs-linux.img
|
boot/initramfs-linux.img
|
||||||
|
|
|
||||||
29
Makefile
29
Makefile
|
|
@ -60,36 +60,35 @@ container:
|
||||||
@echo "Building s390x-archlinux-dev container..."
|
@echo "Building s390x-archlinux-dev container..."
|
||||||
@./scripts/build-container.sh
|
@./scripts/build-container.sh
|
||||||
|
|
||||||
# Test with QEMU (assumes boot files already exist)
|
# Common validation for test targets
|
||||||
test:
|
define check_boot_files
|
||||||
@if [ ! -f "$(BOOT_DIR)/vmlinuz-linux" ] || [ ! -f "$(BOOT_DIR)/initramfs-linux.img" ]; then \
|
@if [ ! -f "$(BOOT_DIR)/vmlinuz-linux" ] || [ ! -f "$(BOOT_DIR)/initramfs-linux.img" ]; then \
|
||||||
echo "Error: Boot files not found. Run 'make all' first"; \
|
echo "Error: Boot files not found. Run 'make all' first"; \
|
||||||
exit 1; \
|
exit 1; \
|
||||||
fi
|
fi
|
||||||
@echo "Testing s390x system with QEMU..."
|
endef
|
||||||
@./scripts/run-qemu-initramfs-only.sh
|
|
||||||
|
|
||||||
# Test with root filesystem (creates minimal rootfs and boots to it)
|
# Test with QEMU (initramfs-only)
|
||||||
|
test:
|
||||||
|
$(call check_boot_files)
|
||||||
|
@echo "Testing s390x system with QEMU (initramfs-only)..."
|
||||||
|
@./scripts/test-qemu.sh initramfs
|
||||||
|
|
||||||
|
# Test with root filesystem
|
||||||
test-rootfs:
|
test-rootfs:
|
||||||
@if [ ! -f "$(BOOT_DIR)/vmlinuz-linux" ] || [ ! -f "$(BOOT_DIR)/initramfs-linux.img" ]; then \
|
$(call check_boot_files)
|
||||||
echo "Error: Boot files not found. Run 'make all' first"; \
|
|
||||||
exit 1; \
|
|
||||||
fi
|
|
||||||
@echo "Testing s390x system with root filesystem..."
|
@echo "Testing s390x system with root filesystem..."
|
||||||
@./scripts/test-qemu-rootfs.sh
|
@./scripts/test-qemu.sh rootfs
|
||||||
|
|
||||||
# Test with systemd as init
|
# Test with systemd as init
|
||||||
test-systemd:
|
test-systemd:
|
||||||
@if [ ! -f "$(BOOT_DIR)/vmlinuz-linux" ] || [ ! -f "$(BOOT_DIR)/initramfs-linux.img" ]; then \
|
$(call check_boot_files)
|
||||||
echo "Error: Boot files not found. Run 'make all' first"; \
|
|
||||||
exit 1; \
|
|
||||||
fi
|
|
||||||
@if [ ! -d "output/systemd-root" ]; then \
|
@if [ ! -d "output/systemd-root" ]; then \
|
||||||
echo "Error: Systemd not found. Run 'make systemd' first"; \
|
echo "Error: Systemd not found. Run 'make systemd' first"; \
|
||||||
exit 1; \
|
exit 1; \
|
||||||
fi
|
fi
|
||||||
@echo "Testing s390x system with systemd..."
|
@echo "Testing s390x system with systemd..."
|
||||||
@./scripts/test-qemu-systemd.sh
|
@./scripts/test-qemu.sh systemd
|
||||||
|
|
||||||
# Create directories
|
# Create directories
|
||||||
$(OUTPUT_DIR):
|
$(OUTPUT_DIR):
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ Arch Linux s390x Boot Directory
|
||||||
==============================
|
==============================
|
||||||
|
|
||||||
Kernel Version: 6.6.10
|
Kernel Version: 6.6.10
|
||||||
Build Date: Thu Jun 5 11:58:54 AM CEST 2025
|
Build Date: Thu Jun 5 03:04:40 PM CEST 2025
|
||||||
Architecture: s390x
|
Architecture: s390x
|
||||||
|
|
||||||
Files:
|
Files:
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -1,105 +0,0 @@
|
||||||
# systemd s390x Big-Endian Patches
|
|
||||||
|
|
||||||
## Overview
|
|
||||||
|
|
||||||
When building systemd for s390x architecture, several big-endian compatibility issues need to be addressed. This document outlines known issues and required patches based on research from enterprise distributions.
|
|
||||||
|
|
||||||
## Known Issues
|
|
||||||
|
|
||||||
### 1. D-Bus Property Endianness
|
|
||||||
|
|
||||||
**Issue**: D-Bus property values may be incorrectly interpreted due to endianness
|
|
||||||
**Symptom**: Values like 131074 (0x20002) instead of expected values
|
|
||||||
**Affected Components**: systemd-resolved, systemd property queries
|
|
||||||
|
|
||||||
**Patch Required**:
|
|
||||||
```patch
|
|
||||||
--- a/src/libsystemd/sd-bus/bus-message.c
|
|
||||||
+++ b/src/libsystemd/sd-bus/bus-message.c
|
|
||||||
@@ -1234,7 +1234,7 @@ static int message_append_basic(sd_bus_message *m, char type, const void *p, co
|
|
||||||
case SD_BUS_TYPE_UINT32:
|
|
||||||
case SD_BUS_TYPE_UNIX_FD:
|
|
||||||
- u32 = *(uint32_t*) p;
|
|
||||||
+ u32 = be32toh(*(uint32_t*) p);
|
|
||||||
p = &u32;
|
|
||||||
align = 4;
|
|
||||||
sz = 4;
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. systemd-resolved Big-Endian Failures
|
|
||||||
|
|
||||||
**Issue**: systemd-resolved fails on big-endian architectures
|
|
||||||
**Symptom**: Service fails to start, D-Bus communication errors
|
|
||||||
**Solution**: Disable systemd-resolved in build configuration (already done in our minimal build)
|
|
||||||
|
|
||||||
### 3. Integration Test Timeouts
|
|
||||||
|
|
||||||
**Issue**: Tests timeout more frequently on s390x
|
|
||||||
**Symptom**: Unit tests fail with timeout errors
|
|
||||||
**Solution**: Increase timeout values or disable tests (already done in our build)
|
|
||||||
|
|
||||||
### 4. /dev/kvm Permissions
|
|
||||||
|
|
||||||
**Issue**: Incorrect permissions on /dev/kvm device
|
|
||||||
**Symptom**: KVM acceleration not available to non-root users
|
|
||||||
**Solution**: Add udev rule for proper permissions
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# /etc/udev/rules.d/99-kvm-s390x.rules
|
|
||||||
KERNEL=="kvm", GROUP="kvm", MODE="0660"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Distribution-Specific Patches
|
|
||||||
|
|
||||||
### SUSE/openSUSE
|
|
||||||
|
|
||||||
SUSE maintains comprehensive s390x patches in their systemd package:
|
|
||||||
- Endianness fixes for D-Bus communication
|
|
||||||
- s390x-specific device handling
|
|
||||||
- Console output improvements
|
|
||||||
|
|
||||||
### Red Hat/Fedora
|
|
||||||
|
|
||||||
Red Hat includes patches for:
|
|
||||||
- Big-endian compatibility in property serialization
|
|
||||||
- s390x hardware console support
|
|
||||||
- Device node permission fixes
|
|
||||||
|
|
||||||
### Ubuntu
|
|
||||||
|
|
||||||
Ubuntu patches focus on:
|
|
||||||
- Integration test reliability
|
|
||||||
- Hardware-specific optimizations
|
|
||||||
- Kernel feature detection
|
|
||||||
|
|
||||||
## Implementation Strategy
|
|
||||||
|
|
||||||
1. **Start with minimal build** - Our configuration already disables problematic components
|
|
||||||
2. **Monitor logs carefully** - Use `systemd.log_level=debug` during initial testing
|
|
||||||
3. **Apply patches incrementally** - Test after each patch to isolate issues
|
|
||||||
4. **Use distribution patches** - Leverage existing work from SUSE/Red Hat/Ubuntu
|
|
||||||
|
|
||||||
## Testing Recommendations
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Enable comprehensive debugging
|
|
||||||
systemd.log_level=debug
|
|
||||||
systemd.journald.forward_to_console=1
|
|
||||||
console=ttysclp0
|
|
||||||
|
|
||||||
# Test in container first
|
|
||||||
systemd-nspawn -bD /test-root --machine=s390x-test
|
|
||||||
|
|
||||||
# Monitor for endianness issues
|
|
||||||
journalctl -f | grep -E "(endian|0x[0-9a-f]+|property|dbus)"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Resources
|
|
||||||
|
|
||||||
- [SUSE systemd s390x patches](https://build.opensuse.org/package/view_file/Base:System/systemd/)
|
|
||||||
- [Red Hat Bugzilla - s390x systemd issues](https://bugzilla.redhat.com/buglist.cgi?product=Fedora&component=systemd&bug_status=__open__&f1=cf_machine&o1=substring&v1=s390x)
|
|
||||||
- [systemd upstream s390x issues](https://github.com/systemd/systemd/issues?q=is%3Aissue+s390x)
|
|
||||||
|
|
||||||
## Conclusion
|
|
||||||
|
|
||||||
While s390x support in systemd requires patches for full functionality, the core init system works reliably. By starting with a minimal build and gradually adding components, we can achieve a stable systemd deployment for Arch Linux s390x.
|
|
||||||
|
|
@ -1,9 +1,19 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# Build static busybox on z/VM s390x RHEL system
|
# Build static busybox on z/VM s390x RHEL system
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
|
||||||
set -e
|
# Source utilities (only common.sh since this runs on z/VM)
|
||||||
|
if [ -f "scripts/common.sh" ]; then
|
||||||
|
source scripts/common.sh
|
||||||
|
else
|
||||||
|
# Minimal logging for z/VM environment
|
||||||
|
log_info() { echo "[INFO] $1"; }
|
||||||
|
log_success() { echo "[SUCCESS] $1"; }
|
||||||
|
log_error() { echo "[ERROR] $1" >&2; }
|
||||||
|
die() { log_error "$1"; exit "${2:-1}"; }
|
||||||
|
fi
|
||||||
|
|
||||||
echo "Building static busybox on native s390x..."
|
log_info "Building static busybox on native s390x..."
|
||||||
|
|
||||||
# Install build dependencies
|
# Install build dependencies
|
||||||
sudo dnf install -y gcc make wget tar bzip2 glibc-static
|
sudo dnf install -y gcc make wget tar bzip2 glibc-static
|
||||||
|
|
|
||||||
286
scripts/common.sh
Normal file
286
scripts/common.sh
Normal file
|
|
@ -0,0 +1,286 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# Common utilities for Arch Linux s390x build system
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
|
||||||
|
# Color definitions
|
||||||
|
export RED='\033[0;31m'
|
||||||
|
export GREEN='\033[0;32m'
|
||||||
|
export YELLOW='\033[1;33m'
|
||||||
|
export BLUE='\033[0;34m'
|
||||||
|
export MAGENTA='\033[0;35m'
|
||||||
|
export CYAN='\033[0;36m'
|
||||||
|
export NC='\033[0m'
|
||||||
|
|
||||||
|
# Get project root directory
|
||||||
|
get_project_root() {
|
||||||
|
local script_dir="$(cd "$(dirname "${BASH_SOURCE[1]}")" && pwd)"
|
||||||
|
echo "$(dirname "$script_dir")"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Get project paths
|
||||||
|
get_project_paths() {
|
||||||
|
export PROJECT_ROOT="$(get_project_root)"
|
||||||
|
export OUTPUT_DIR="$PROJECT_ROOT/output"
|
||||||
|
export BOOT_DIR="$PROJECT_ROOT/boot"
|
||||||
|
export BUILD_DIR="$PROJECT_ROOT/build-kernel"
|
||||||
|
export SCRIPTS_DIR="$PROJECT_ROOT/scripts"
|
||||||
|
export PATCHES_DIR="$PROJECT_ROOT/patches"
|
||||||
|
export CONFIG_DIR="$PROJECT_ROOT/config"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Logging functions
|
||||||
|
log_info() {
|
||||||
|
echo -e "${BLUE}[INFO]${NC} $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
log_success() {
|
||||||
|
echo -e "${GREEN}[SUCCESS]${NC} $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
log_warning() {
|
||||||
|
echo -e "${YELLOW}[WARNING]${NC} $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
log_error() {
|
||||||
|
echo -e "${RED}[ERROR]${NC} $1" >&2
|
||||||
|
}
|
||||||
|
|
||||||
|
log_debug() {
|
||||||
|
if [ "${DEBUG:-0}" = "1" ]; then
|
||||||
|
echo -e "${MAGENTA}[DEBUG]${NC} $1" >&2
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Error handling
|
||||||
|
die() {
|
||||||
|
log_error "$1"
|
||||||
|
exit "${2:-1}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check if command exists
|
||||||
|
command_exists() {
|
||||||
|
command -v "$1" >/dev/null 2>&1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check if running in container
|
||||||
|
is_container() {
|
||||||
|
[ -f /.dockerenv ] || [ -f /run/.containerenv ] || [ "${container:-}" = "podman" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
# Validate required commands
|
||||||
|
check_required_commands() {
|
||||||
|
local missing=()
|
||||||
|
for cmd in "$@"; do
|
||||||
|
if ! command_exists "$cmd"; then
|
||||||
|
missing+=("$cmd")
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ ${#missing[@]} -gt 0 ]; then
|
||||||
|
log_error "Missing required commands: ${missing[*]}"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Validate required files
|
||||||
|
check_required_files() {
|
||||||
|
local missing=()
|
||||||
|
for file in "$@"; do
|
||||||
|
if [ ! -f "$file" ]; then
|
||||||
|
missing+=("$file")
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ ${#missing[@]} -gt 0 ]; then
|
||||||
|
log_error "Missing required files: ${missing[*]}"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Validate required directories
|
||||||
|
check_required_dirs() {
|
||||||
|
local missing=()
|
||||||
|
for dir in "$@"; do
|
||||||
|
if [ ! -d "$dir" ]; then
|
||||||
|
missing+=("$dir")
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ ${#missing[@]} -gt 0 ]; then
|
||||||
|
log_error "Missing required directories: ${missing[*]}"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Create directory if it doesn't exist
|
||||||
|
ensure_dir() {
|
||||||
|
local dir="$1"
|
||||||
|
if [ ! -d "$dir" ]; then
|
||||||
|
log_debug "Creating directory: $dir"
|
||||||
|
mkdir -p "$dir" || die "Failed to create directory: $dir"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Load environment from .env file if it exists
|
||||||
|
load_env() {
|
||||||
|
local env_file="${1:-.env}"
|
||||||
|
if [ -f "$env_file" ]; then
|
||||||
|
log_debug "Loading environment from $env_file"
|
||||||
|
set -a
|
||||||
|
source "$env_file"
|
||||||
|
set +a
|
||||||
|
log_debug "Environment loaded successfully"
|
||||||
|
else
|
||||||
|
log_debug "No .env file found at $env_file"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Print script header
|
||||||
|
print_header() {
|
||||||
|
local title="$1"
|
||||||
|
local width=60
|
||||||
|
echo
|
||||||
|
echo -e "${CYAN}$(printf '=%.0s' $(seq 1 $width))${NC}"
|
||||||
|
echo -e "${CYAN}$(printf '%-*s' $width "$title")${NC}"
|
||||||
|
echo -e "${CYAN}$(printf '=%.0s' $(seq 1 $width))${NC}"
|
||||||
|
echo
|
||||||
|
}
|
||||||
|
|
||||||
|
# Print section separator
|
||||||
|
print_section() {
|
||||||
|
local title="$1"
|
||||||
|
echo
|
||||||
|
echo -e "${YELLOW}=== $title ===${NC}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Cleanup function for temporary files
|
||||||
|
cleanup_on_exit() {
|
||||||
|
local temp_files=("$@")
|
||||||
|
for file in "${temp_files[@]}"; do
|
||||||
|
if [ -f "$file" ]; then
|
||||||
|
log_debug "Cleaning up temporary file: $file"
|
||||||
|
rm -f "$file"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
# Set up cleanup trap
|
||||||
|
setup_cleanup() {
|
||||||
|
local temp_files=("$@")
|
||||||
|
trap 'cleanup_on_exit "${temp_files[@]}"' EXIT INT TERM
|
||||||
|
}
|
||||||
|
|
||||||
|
# Progress indicator
|
||||||
|
show_progress() {
|
||||||
|
local current="$1"
|
||||||
|
local total="$2"
|
||||||
|
local message="$3"
|
||||||
|
local width=40
|
||||||
|
local progress=$((current * width / total))
|
||||||
|
local remaining=$((width - progress))
|
||||||
|
|
||||||
|
printf "\r${CYAN}[%s%s] %d/%d %s${NC}" \
|
||||||
|
"$(printf '#%.0s' $(seq 1 $progress))" \
|
||||||
|
"$(printf '.%.0s' $(seq 1 $remaining))" \
|
||||||
|
"$current" "$total" "$message"
|
||||||
|
|
||||||
|
if [ "$current" -eq "$total" ]; then
|
||||||
|
echo
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Timer functions
|
||||||
|
start_timer() {
|
||||||
|
export TIMER_START=$(date +%s)
|
||||||
|
}
|
||||||
|
|
||||||
|
end_timer() {
|
||||||
|
local start_time="${TIMER_START:-$(date +%s)}"
|
||||||
|
local end_time=$(date +%s)
|
||||||
|
local duration=$((end_time - start_time))
|
||||||
|
local minutes=$((duration / 60))
|
||||||
|
local seconds=$((duration % 60))
|
||||||
|
|
||||||
|
if [ $minutes -gt 0 ]; then
|
||||||
|
echo -e "${CYAN}Completed in ${minutes}m ${seconds}s${NC}"
|
||||||
|
else
|
||||||
|
echo -e "${CYAN}Completed in ${seconds}s${NC}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# File size formatting
|
||||||
|
format_size() {
|
||||||
|
local size="$1"
|
||||||
|
if [ "$size" -ge 1073741824 ]; then
|
||||||
|
echo "$((size / 1073741824))GB"
|
||||||
|
elif [ "$size" -ge 1048576 ]; then
|
||||||
|
echo "$((size / 1048576))MB"
|
||||||
|
elif [ "$size" -ge 1024 ]; then
|
||||||
|
echo "$((size / 1024))KB"
|
||||||
|
else
|
||||||
|
echo "${size}B"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Get file size in human readable format
|
||||||
|
get_file_size() {
|
||||||
|
local file="$1"
|
||||||
|
if [ -f "$file" ]; then
|
||||||
|
local size=$(stat -c%s "$file" 2>/dev/null || stat -f%z "$file" 2>/dev/null)
|
||||||
|
format_size "$size"
|
||||||
|
else
|
||||||
|
echo "N/A"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Common QEMU configuration
|
||||||
|
run_qemu_s390x() {
|
||||||
|
local append_args="$1"
|
||||||
|
local extra_args="${2:-}"
|
||||||
|
|
||||||
|
check_required_commands qemu-system-s390x
|
||||||
|
check_required_files "boot/vmlinuz-linux" "boot/initramfs-linux.img"
|
||||||
|
|
||||||
|
log_info "Starting QEMU s390x system..."
|
||||||
|
log_debug "Append args: $append_args"
|
||||||
|
log_debug "Extra args: $extra_args"
|
||||||
|
|
||||||
|
qemu-system-s390x \
|
||||||
|
-machine s390-ccw-virtio \
|
||||||
|
-cpu max \
|
||||||
|
-m 2G \
|
||||||
|
-kernel "boot/vmlinuz-linux" \
|
||||||
|
-initrd "boot/initramfs-linux.img" \
|
||||||
|
-append "console=ttyS0 $append_args" \
|
||||||
|
-nographic \
|
||||||
|
-device virtio-net-ccw,netdev=net0 \
|
||||||
|
-netdev user,id=net0 \
|
||||||
|
$extra_args
|
||||||
|
}
|
||||||
|
|
||||||
|
# Initialize common environment
|
||||||
|
init_common() {
|
||||||
|
# Set strict error handling
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Initialize paths
|
||||||
|
get_project_paths
|
||||||
|
|
||||||
|
# Load environment if available
|
||||||
|
load_env
|
||||||
|
|
||||||
|
# Ensure output directory exists
|
||||||
|
ensure_dir "$OUTPUT_DIR"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Export functions for use in other scripts
|
||||||
|
export -f get_project_root get_project_paths
|
||||||
|
export -f log_info log_success log_warning log_error log_debug die
|
||||||
|
export -f command_exists is_container
|
||||||
|
export -f check_required_commands check_required_files check_required_dirs
|
||||||
|
export -f ensure_dir load_env
|
||||||
|
export -f print_header print_section
|
||||||
|
export -f cleanup_on_exit setup_cleanup
|
||||||
|
export -f show_progress start_timer end_timer
|
||||||
|
export -f format_size get_file_size
|
||||||
|
export -f run_qemu_s390x init_common
|
||||||
581
scripts/create-rootfs.sh
Normal file
581
scripts/create-rootfs.sh
Normal file
|
|
@ -0,0 +1,581 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# Root filesystem creation utilities for Arch Linux s390x
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
|
||||||
|
# Source common utilities
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
source "$SCRIPT_DIR/common.sh"
|
||||||
|
|
||||||
|
# Root filesystem configuration
|
||||||
|
export DEFAULT_ROOTFS_SIZE="150"
|
||||||
|
export DEFAULT_ROOTFS_NAME="rootfs-s390x.img"
|
||||||
|
export ROOTFS_MOUNT_POINT="/tmp/rootfs-mount"
|
||||||
|
|
||||||
|
# Create basic root filesystem structure
|
||||||
|
create_rootfs_structure() {
|
||||||
|
local mount_point="$1"
|
||||||
|
|
||||||
|
log_info "Creating root filesystem directory structure..."
|
||||||
|
|
||||||
|
# Create standard Linux directory structure
|
||||||
|
local dirs=(
|
||||||
|
"bin" "sbin" "etc" "proc" "sys" "dev" "tmp" "var" "usr/bin" "usr/sbin"
|
||||||
|
"lib" "lib64" "run" "boot" "home" "root" "opt" "srv" "mnt" "media"
|
||||||
|
"etc/systemd/system" "var/log" "var/log/journal" "var/tmp"
|
||||||
|
"usr/lib" "usr/lib64" "usr/share" "usr/include" "usr/src"
|
||||||
|
)
|
||||||
|
|
||||||
|
for dir in "${dirs[@]}"; do
|
||||||
|
sudo mkdir -p "$mount_point/$dir"
|
||||||
|
log_debug "Created directory: $dir"
|
||||||
|
done
|
||||||
|
|
||||||
|
log_success "Directory structure created"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Create essential device nodes
|
||||||
|
create_device_nodes() {
|
||||||
|
local mount_point="$1"
|
||||||
|
|
||||||
|
log_info "Creating essential device nodes..."
|
||||||
|
|
||||||
|
# Console and TTY devices
|
||||||
|
sudo mknod "$mount_point/dev/console" c 5 1 2>/dev/null || true
|
||||||
|
sudo mknod "$mount_point/dev/tty" c 5 0 2>/dev/null || true
|
||||||
|
|
||||||
|
# TTY devices for virtual terminals
|
||||||
|
for i in {1..4}; do
|
||||||
|
sudo mknod "$mount_point/dev/tty$i" c 4 $i 2>/dev/null || true
|
||||||
|
done
|
||||||
|
|
||||||
|
# Null and zero devices
|
||||||
|
sudo mknod "$mount_point/dev/null" c 1 3 2>/dev/null || true
|
||||||
|
sudo mknod "$mount_point/dev/zero" c 1 5 2>/dev/null || true
|
||||||
|
sudo mknod "$mount_point/dev/random" c 1 8 2>/dev/null || true
|
||||||
|
sudo mknod "$mount_point/dev/urandom" c 1 9 2>/dev/null || true
|
||||||
|
|
||||||
|
log_success "Device nodes created"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Create basic system files
|
||||||
|
create_system_files() {
|
||||||
|
local mount_point="$1"
|
||||||
|
|
||||||
|
log_info "Creating basic system files..."
|
||||||
|
|
||||||
|
# /etc/passwd
|
||||||
|
sudo tee "$mount_point/etc/passwd" > /dev/null << 'EOF'
|
||||||
|
root:x:0:0:root:/root:/bin/sh
|
||||||
|
bin:x:1:1:bin:/bin:/usr/bin/nologin
|
||||||
|
daemon:x:2:2:daemon:/:/usr/bin/nologin
|
||||||
|
nobody:x:65534:65534:Kernel Overflow User:/:/usr/bin/nologin
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# /etc/group
|
||||||
|
sudo tee "$mount_point/etc/group" > /dev/null << 'EOF'
|
||||||
|
root:x:0:
|
||||||
|
bin:x:1:
|
||||||
|
daemon:x:2:
|
||||||
|
sys:x:3:
|
||||||
|
adm:x:4:
|
||||||
|
tty:x:5:
|
||||||
|
disk:x:6:
|
||||||
|
lp:x:7:
|
||||||
|
mail:x:8:
|
||||||
|
news:x:9:
|
||||||
|
uucp:x:10:
|
||||||
|
man:x:12:
|
||||||
|
proxy:x:13:
|
||||||
|
kmem:x:15:
|
||||||
|
dialout:x:20:
|
||||||
|
fax:x:21:
|
||||||
|
voice:x:22:
|
||||||
|
cdrom:x:24:
|
||||||
|
floppy:x:25:
|
||||||
|
tape:x:26:
|
||||||
|
sudo:x:27:
|
||||||
|
audio:x:29:
|
||||||
|
dip:x:30:
|
||||||
|
www-data:x:33:
|
||||||
|
backup:x:34:
|
||||||
|
operator:x:37:
|
||||||
|
list:x:38:
|
||||||
|
irc:x:39:
|
||||||
|
src:x:40:
|
||||||
|
gnats:x:41:
|
||||||
|
shadow:x:42:
|
||||||
|
utmp:x:43:
|
||||||
|
video:x:44:
|
||||||
|
sasl:x:45:
|
||||||
|
plugdev:x:46:
|
||||||
|
staff:x:50:
|
||||||
|
games:x:60:
|
||||||
|
users:x:100:
|
||||||
|
nogroup:x:65534:
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# /etc/shadow
|
||||||
|
sudo tee "$mount_point/etc/shadow" > /dev/null << 'EOF'
|
||||||
|
root::19797:0:99999:7:::
|
||||||
|
bin:*:19797:0:99999:7:::
|
||||||
|
daemon:*:19797:0:99999:7:::
|
||||||
|
nobody:*:19797:0:99999:7:::
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# /etc/os-release (Arch Linux identification)
|
||||||
|
sudo tee "$mount_point/etc/os-release" > /dev/null << 'EOF'
|
||||||
|
NAME="Arch Linux"
|
||||||
|
PRETTY_NAME="Arch Linux"
|
||||||
|
ID=arch
|
||||||
|
BUILD_ID=rolling
|
||||||
|
ANSI_COLOR="38;2;23;147;209"
|
||||||
|
HOME_URL="https://archlinux.org/"
|
||||||
|
DOCUMENTATION_URL="https://wiki.archlinux.org/"
|
||||||
|
SUPPORT_URL="https://bbs.archlinux.org/"
|
||||||
|
BUG_REPORT_URL="https://bugs.archlinux.org/"
|
||||||
|
PRIVACY_POLICY_URL="https://terms.archlinux.org/docs/privacy-policy/"
|
||||||
|
LOGO=archlinux-logo
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# /etc/arch-release
|
||||||
|
sudo tee "$mount_point/etc/arch-release" > /dev/null << 'EOF'
|
||||||
|
Arch Linux \r (\l)
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# /etc/hostname
|
||||||
|
sudo tee "$mount_point/etc/hostname" > /dev/null << 'EOF'
|
||||||
|
archlinux-s390x
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# /etc/hosts
|
||||||
|
sudo tee "$mount_point/etc/hosts" > /dev/null << 'EOF'
|
||||||
|
127.0.0.1 localhost
|
||||||
|
::1 localhost
|
||||||
|
127.0.1.1 archlinux-s390x.localdomain archlinux-s390x
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# /etc/fstab
|
||||||
|
sudo tee "$mount_point/etc/fstab" > /dev/null << 'EOF'
|
||||||
|
# Static information about the filesystems.
|
||||||
|
# See fstab(5) for details.
|
||||||
|
|
||||||
|
# <file system> <dir> <type> <options> <dump> <pass>
|
||||||
|
/dev/vda / ext4 rw,relatime 0 1
|
||||||
|
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
|
||||||
|
|
||||||
|
log_success "System files created"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Install busybox with applets
|
||||||
|
install_busybox() {
|
||||||
|
local mount_point="$1"
|
||||||
|
local busybox_binary="${2:-boot/busybox-s390x-static}"
|
||||||
|
|
||||||
|
log_info "Installing busybox..."
|
||||||
|
|
||||||
|
if [ ! -f "$busybox_binary" ]; then
|
||||||
|
log_error "Busybox binary not found: $busybox_binary"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Copy busybox binary
|
||||||
|
sudo cp "$busybox_binary" "$mount_point/bin/busybox"
|
||||||
|
sudo chmod +x "$mount_point/bin/busybox"
|
||||||
|
|
||||||
|
# Install busybox applets
|
||||||
|
log_info "Installing busybox applets..."
|
||||||
|
sudo chroot "$mount_point" /bin/busybox --install -s
|
||||||
|
|
||||||
|
# Verify critical applets and create missing ones
|
||||||
|
local critical_applets=("sh" "mount" "umount" "switch_root" "init")
|
||||||
|
for applet in "${critical_applets[@]}"; do
|
||||||
|
if [ -L "$mount_point/bin/$applet" ] || [ -f "$mount_point/bin/$applet" ]; then
|
||||||
|
log_debug "Applet installed: $applet"
|
||||||
|
else
|
||||||
|
log_debug "Creating missing applet symlink: $applet"
|
||||||
|
sudo ln -sf busybox "$mount_point/bin/$applet"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
log_success "Busybox installed with applets"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Install systemd components
|
||||||
|
install_systemd() {
|
||||||
|
local mount_point="$1"
|
||||||
|
local systemd_root="${2:-output/systemd-root}"
|
||||||
|
|
||||||
|
log_info "Installing systemd components..."
|
||||||
|
|
||||||
|
if [ ! -d "$systemd_root" ]; then
|
||||||
|
log_error "Systemd root directory not found: $systemd_root"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Copy systemd files
|
||||||
|
sudo cp -r "$systemd_root"/* "$mount_point/"
|
||||||
|
|
||||||
|
# Create systemd directories
|
||||||
|
sudo mkdir -p "$mount_point/run/systemd"
|
||||||
|
sudo mkdir -p "$mount_point/var/log/journal"
|
||||||
|
sudo mkdir -p "$mount_point/etc/systemd/system"
|
||||||
|
sudo mkdir -p "$mount_point/usr/lib/systemd/system"
|
||||||
|
|
||||||
|
# Set permissions
|
||||||
|
sudo chmod 755 "$mount_point/usr/lib/systemd/systemd"
|
||||||
|
|
||||||
|
# Configure systemd for easy access
|
||||||
|
configure_systemd_for_testing "$mount_point"
|
||||||
|
|
||||||
|
log_success "Systemd components installed"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Configure systemd for easier testing access
|
||||||
|
configure_systemd_for_testing() {
|
||||||
|
local mount_point="$1"
|
||||||
|
|
||||||
|
log_info "Configuring systemd for testing access..."
|
||||||
|
|
||||||
|
# Set root password to empty (no password required)
|
||||||
|
sudo sed -i 's/^root::/root::/' "$mount_point/etc/shadow"
|
||||||
|
|
||||||
|
# Disable first boot wizard by creating marker files
|
||||||
|
sudo mkdir -p "$mount_point/var/lib/systemd"
|
||||||
|
|
||||||
|
# Create machine-id to skip first boot setup (as file, not directory)
|
||||||
|
sudo sh -c "uuidgen | tr -d '-' > '$mount_point/etc/machine-id'"
|
||||||
|
sudo touch "$mount_point/var/lib/systemd/first-boot"
|
||||||
|
|
||||||
|
# Create a simple auto-login service for ttyS0
|
||||||
|
sudo tee "$mount_point/etc/systemd/system/autologin-ttyS0.service" > /dev/null << 'EOF'
|
||||||
|
[Unit]
|
||||||
|
Description=Auto Login on ttyS0
|
||||||
|
After=systemd-user-sessions.service plymouth-quit-wait.service
|
||||||
|
Before=getty.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
ExecStart=/bin/sh -c 'echo "Auto-login as root on ttyS0"; exec /bin/sh'
|
||||||
|
Type=idle
|
||||||
|
Restart=always
|
||||||
|
RestartSec=0
|
||||||
|
StandardInput=tty
|
||||||
|
StandardOutput=tty
|
||||||
|
StandardError=tty
|
||||||
|
TTYPath=/dev/ttyS0
|
||||||
|
TTYReset=yes
|
||||||
|
TTYVHangup=yes
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=getty.target
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Create a simple auto-login service for ttysclp0
|
||||||
|
sudo tee "$mount_point/etc/systemd/system/autologin-ttysclp0.service" > /dev/null << 'EOF'
|
||||||
|
[Unit]
|
||||||
|
Description=Auto Login on ttysclp0
|
||||||
|
After=systemd-user-sessions.service plymouth-quit-wait.service
|
||||||
|
Before=getty.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
ExecStart=/bin/sh -c 'echo "Auto-login as root on ttysclp0"; exec /bin/sh'
|
||||||
|
Type=idle
|
||||||
|
Restart=always
|
||||||
|
RestartSec=0
|
||||||
|
StandardInput=tty
|
||||||
|
StandardOutput=tty
|
||||||
|
StandardError=tty
|
||||||
|
TTYPath=/dev/ttysclp0
|
||||||
|
TTYReset=yes
|
||||||
|
TTYVHangup=yes
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=getty.target
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Disable/mask services that interfere with testing
|
||||||
|
sudo mkdir -p "$mount_point/etc/systemd/system"
|
||||||
|
sudo ln -sf "/dev/null" "$mount_point/etc/systemd/system/systemd-firstboot.service"
|
||||||
|
sudo ln -sf "/dev/null" "$mount_point/etc/systemd/system/getty@tty1.service"
|
||||||
|
sudo ln -sf "/dev/null" "$mount_point/etc/systemd/system/serial-getty@ttyS0.service"
|
||||||
|
sudo ln -sf "/dev/null" "$mount_point/etc/systemd/system/serial-getty@ttysclp0.service"
|
||||||
|
|
||||||
|
# Enable the auto-login services
|
||||||
|
sudo mkdir -p "$mount_point/etc/systemd/system/getty.target.wants"
|
||||||
|
sudo ln -sf "/etc/systemd/system/autologin-ttyS0.service" "$mount_point/etc/systemd/system/getty.target.wants/"
|
||||||
|
sudo ln -sf "/etc/systemd/system/autologin-ttysclp0.service" "$mount_point/etc/systemd/system/getty.target.wants/"
|
||||||
|
|
||||||
|
# Create a simple .bashrc for root to show system info
|
||||||
|
sudo tee "$mount_point/root/.bashrc" > /dev/null << 'EOF'
|
||||||
|
# Arch Linux s390x Root Shell
|
||||||
|
echo "Welcome to Arch Linux s390x with systemd!"
|
||||||
|
echo
|
||||||
|
echo "=== System Information ==="
|
||||||
|
echo "Architecture: $(uname -m)"
|
||||||
|
echo "Kernel: $(uname -r)"
|
||||||
|
echo "Systemd version: $(systemctl --version | head -n1)"
|
||||||
|
echo "Hostname: $(hostname)"
|
||||||
|
echo
|
||||||
|
echo "=== Systemd Status ==="
|
||||||
|
echo "Boot time: $(systemd-analyze | head -n1 2>/dev/null || echo 'Not available')"
|
||||||
|
echo "Failed units: $(systemctl --failed --no-legend | wc -l) unit(s)"
|
||||||
|
echo
|
||||||
|
echo "=== Available Commands ==="
|
||||||
|
echo "systemctl status - Show systemd status"
|
||||||
|
echo "systemctl --failed - Show failed services"
|
||||||
|
echo "journalctl -f - Follow system logs"
|
||||||
|
echo "poweroff - Shutdown system"
|
||||||
|
echo
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Create emergency shell service
|
||||||
|
sudo tee "$mount_point/etc/systemd/system/emergency-shell.service" > /dev/null << 'EOF'
|
||||||
|
[Unit]
|
||||||
|
Description=Emergency Shell
|
||||||
|
DefaultDependencies=false
|
||||||
|
Conflicts=shutdown.target
|
||||||
|
Before=shutdown.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=idle
|
||||||
|
ExecStart=/bin/sh
|
||||||
|
StandardInput=tty-force
|
||||||
|
StandardOutput=inherit
|
||||||
|
StandardError=inherit
|
||||||
|
KillMode=process
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=emergency.target
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Add a service to show boot completion
|
||||||
|
sudo tee "$mount_point/etc/systemd/system/boot-complete.service" > /dev/null << 'EOF'
|
||||||
|
[Unit]
|
||||||
|
Description=Boot Completion Notification
|
||||||
|
After=multi-user.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=oneshot
|
||||||
|
ExecStart=/bin/sh -c 'echo "🚀 Arch Linux s390x boot completed successfully!"'
|
||||||
|
RemainAfterExit=yes
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Enable the boot completion service
|
||||||
|
sudo mkdir -p "$mount_point/etc/systemd/system/multi-user.target.wants"
|
||||||
|
sudo ln -sf "/usr/lib/systemd/system/boot-complete.service" "$mount_point/etc/systemd/system/multi-user.target.wants/boot-complete.service"
|
||||||
|
|
||||||
|
log_success "Systemd configured for testing"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Create init script
|
||||||
|
create_init_script() {
|
||||||
|
local mount_point="$1"
|
||||||
|
local use_systemd="${2:-false}"
|
||||||
|
|
||||||
|
log_info "Creating init script (systemd: $use_systemd)..."
|
||||||
|
|
||||||
|
if [ "$use_systemd" = "true" ]; then
|
||||||
|
# Create systemd init wrapper
|
||||||
|
sudo tee "$mount_point/sbin/init" > /dev/null << 'EOF'
|
||||||
|
#!/bin/sh
|
||||||
|
echo "Starting Arch Linux s390x with systemd..."
|
||||||
|
|
||||||
|
# Mount essential filesystems
|
||||||
|
mount -t proc proc /proc 2>/dev/null || true
|
||||||
|
mount -t sysfs sysfs /sys 2>/dev/null || true
|
||||||
|
mount -t devtmpfs devtmpfs /dev 2>/dev/null || true
|
||||||
|
mount -t tmpfs tmpfs /run 2>/dev/null || true
|
||||||
|
mount -t tmpfs tmpfs /tmp 2>/dev/null || true
|
||||||
|
|
||||||
|
# Create required directories
|
||||||
|
mkdir -p /run/systemd /var/log/journal
|
||||||
|
|
||||||
|
echo "=== Starting systemd ==="
|
||||||
|
exec /usr/lib/systemd/systemd
|
||||||
|
EOF
|
||||||
|
else
|
||||||
|
# Create busybox init script
|
||||||
|
sudo tee "$mount_point/sbin/init" > /dev/null << 'EOF'
|
||||||
|
#!/bin/sh
|
||||||
|
echo "Welcome to Arch Linux s390x Root Filesystem!"
|
||||||
|
|
||||||
|
# Mount essential filesystems
|
||||||
|
mount -t proc proc /proc 2>/dev/null || true
|
||||||
|
mount -t sysfs sysfs /sys 2>/dev/null || true
|
||||||
|
mount -t devtmpfs devtmpfs /dev 2>/dev/null || true
|
||||||
|
|
||||||
|
# Create TTY devices if they don't exist
|
||||||
|
for i in 1 2 3 4; do
|
||||||
|
[ ! -c /dev/tty$i ] && mknod /dev/tty$i c 4 $i 2>/dev/null || true
|
||||||
|
done
|
||||||
|
[ ! -c /dev/console ] && mknod /dev/console c 5 1 2>/dev/null || true
|
||||||
|
|
||||||
|
echo "=== ARCH LINUX VERIFICATION ==="
|
||||||
|
[ -f /etc/os-release ] && cat /etc/os-release
|
||||||
|
echo "Architecture: $(uname -m)"
|
||||||
|
echo "Kernel: $(uname -r)"
|
||||||
|
echo "Init: Busybox $(busybox | head -n1)"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== ROOT FILESYSTEM READY ==="
|
||||||
|
echo "You are now in the Arch Linux s390x root filesystem!"
|
||||||
|
echo "Available commands: $(busybox --list | tr '\n' ' ')"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Start shell
|
||||||
|
exec /bin/sh
|
||||||
|
EOF
|
||||||
|
fi
|
||||||
|
|
||||||
|
sudo chmod +x "$mount_point/sbin/init"
|
||||||
|
log_success "Init script created"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Mount root filesystem image
|
||||||
|
mount_rootfs() {
|
||||||
|
local rootfs_image="$1"
|
||||||
|
local mount_point="${2:-$ROOTFS_MOUNT_POINT}"
|
||||||
|
|
||||||
|
log_info "Mounting root filesystem: $rootfs_image"
|
||||||
|
|
||||||
|
if [ ! -f "$rootfs_image" ]; then
|
||||||
|
die "Root filesystem image not found: $rootfs_image"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create mount point
|
||||||
|
ensure_dir "$mount_point"
|
||||||
|
|
||||||
|
# Check if already mounted
|
||||||
|
if mountpoint -q "$mount_point" 2>/dev/null; then
|
||||||
|
log_warning "Filesystem already mounted at $mount_point"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Mount the image
|
||||||
|
sudo mount -o loop "$rootfs_image" "$mount_point" || die "Failed to mount $rootfs_image"
|
||||||
|
|
||||||
|
log_success "Filesystem mounted at $mount_point"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Unmount root filesystem
|
||||||
|
unmount_rootfs() {
|
||||||
|
local mount_point="${1:-$ROOTFS_MOUNT_POINT}"
|
||||||
|
|
||||||
|
if mountpoint -q "$mount_point" 2>/dev/null; then
|
||||||
|
log_info "Unmounting filesystem at $mount_point"
|
||||||
|
sudo umount "$mount_point" || log_warning "Failed to unmount $mount_point"
|
||||||
|
rmdir "$mount_point" 2>/dev/null || true
|
||||||
|
log_success "Filesystem unmounted"
|
||||||
|
else
|
||||||
|
log_debug "No filesystem mounted at $mount_point"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Create complete root filesystem
|
||||||
|
create_rootfs() {
|
||||||
|
local rootfs_image="$1"
|
||||||
|
local size_mb="${2:-$DEFAULT_ROOTFS_SIZE}"
|
||||||
|
local install_systemd="${3:-false}"
|
||||||
|
local busybox_binary="${4:-boot/busybox-s390x-static}"
|
||||||
|
local systemd_root="${5:-output/systemd-root}"
|
||||||
|
|
||||||
|
print_header "Creating Root Filesystem: $rootfs_image"
|
||||||
|
start_timer
|
||||||
|
|
||||||
|
# Cleanup any existing mount
|
||||||
|
unmount_rootfs
|
||||||
|
|
||||||
|
# Remove existing image
|
||||||
|
if [ -f "$rootfs_image" ]; then
|
||||||
|
log_info "Removing existing root filesystem image..."
|
||||||
|
rm -f "$rootfs_image"
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_info "Creating ${size_mb}MB root filesystem image..."
|
||||||
|
|
||||||
|
# Create and format filesystem
|
||||||
|
dd if=/dev/zero of="$rootfs_image" bs=1M count="$size_mb" status=progress
|
||||||
|
mkfs.ext4 -F "$rootfs_image"
|
||||||
|
|
||||||
|
# Mount filesystem
|
||||||
|
mount_rootfs "$rootfs_image"
|
||||||
|
|
||||||
|
# Create directory structure
|
||||||
|
create_rootfs_structure "$ROOTFS_MOUNT_POINT"
|
||||||
|
|
||||||
|
# Create device nodes
|
||||||
|
create_device_nodes "$ROOTFS_MOUNT_POINT"
|
||||||
|
|
||||||
|
# Create system files
|
||||||
|
create_system_files "$ROOTFS_MOUNT_POINT"
|
||||||
|
|
||||||
|
# Install busybox
|
||||||
|
install_busybox "$ROOTFS_MOUNT_POINT" "$busybox_binary"
|
||||||
|
|
||||||
|
# Install systemd if requested
|
||||||
|
if [ "$install_systemd" = "true" ]; then
|
||||||
|
install_systemd "$ROOTFS_MOUNT_POINT" "$systemd_root"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create init script
|
||||||
|
create_init_script "$ROOTFS_MOUNT_POINT" "$install_systemd"
|
||||||
|
|
||||||
|
# Unmount filesystem
|
||||||
|
unmount_rootfs
|
||||||
|
|
||||||
|
# Show final information
|
||||||
|
local size=$(get_file_size "$rootfs_image")
|
||||||
|
log_success "Root filesystem created: $rootfs_image ($size)"
|
||||||
|
|
||||||
|
if [ "$install_systemd" = "true" ]; then
|
||||||
|
log_info "Systemd support: ENABLED"
|
||||||
|
else
|
||||||
|
log_info "Init system: Busybox"
|
||||||
|
fi
|
||||||
|
|
||||||
|
end_timer
|
||||||
|
}
|
||||||
|
|
||||||
|
# Quick root filesystem creation functions
|
||||||
|
create_initramfs_rootfs() {
|
||||||
|
local rootfs_image="${1:-boot/$DEFAULT_ROOTFS_NAME}"
|
||||||
|
create_rootfs "$rootfs_image" 50 false
|
||||||
|
}
|
||||||
|
|
||||||
|
create_busybox_rootfs() {
|
||||||
|
local rootfs_image="${1:-boot/$DEFAULT_ROOTFS_NAME}"
|
||||||
|
local size_mb="${2:-150}"
|
||||||
|
create_rootfs "$rootfs_image" "$size_mb" false
|
||||||
|
}
|
||||||
|
|
||||||
|
create_systemd_rootfs() {
|
||||||
|
local rootfs_image="${1:-boot/$DEFAULT_ROOTFS_NAME}"
|
||||||
|
local size_mb="${2:-200}"
|
||||||
|
create_rootfs "$rootfs_image" "$size_mb" true
|
||||||
|
}
|
||||||
|
|
||||||
|
# Initialize rootfs utilities
|
||||||
|
init_rootfs() {
|
||||||
|
init_common
|
||||||
|
|
||||||
|
# Check required commands
|
||||||
|
check_required_commands dd mkfs.ext4 mount umount sudo
|
||||||
|
|
||||||
|
# Set up cleanup trap for mount point
|
||||||
|
setup_cleanup "$ROOTFS_MOUNT_POINT"
|
||||||
|
|
||||||
|
log_debug "Root filesystem utilities initialized"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Export functions for use in other scripts
|
||||||
|
export -f create_rootfs_structure create_device_nodes create_system_files
|
||||||
|
export -f install_busybox install_systemd create_init_script
|
||||||
|
export -f mount_rootfs unmount_rootfs create_rootfs
|
||||||
|
export -f create_initramfs_rootfs create_busybox_rootfs create_systemd_rootfs
|
||||||
|
export -f init_rootfs
|
||||||
|
|
@ -1,116 +1,52 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# Build systemd on z/VM using scp to transfer files
|
# Build systemd on z/VM using scp to transfer files
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
|
||||||
set -e
|
# Source utilities
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
source "$SCRIPT_DIR/common.sh"
|
||||||
|
source "$SCRIPT_DIR/zvm-utils.sh"
|
||||||
|
|
||||||
# Colors
|
# Initialize z/VM environment
|
||||||
RED='\033[0;31m'
|
init_zvm
|
||||||
GREEN='\033[0;32m'
|
|
||||||
YELLOW='\033[1;33m'
|
|
||||||
NC='\033[0m'
|
|
||||||
|
|
||||||
# Load environment variables from .env file if available and variables not set
|
# Build systemd using the z/VM utilities
|
||||||
if [ -z "$ZVM_HOST" ] || [ -z "$ZVM_USER" ]; then
|
build_on_zvm "systemd" "scripts/build-systemd-zvm.sh" "systemd-minimal-s390x.tar.gz" 1800
|
||||||
if [ -f ".env" ]; then
|
|
||||||
echo -e "${YELLOW}Loading z/VM configuration from .env file...${NC}"
|
|
||||||
set -a # Export all variables
|
|
||||||
source .env
|
|
||||||
set +a # Stop exporting
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Check if required variables are now set
|
# Extract and organize systemd
|
||||||
if [ -z "$ZVM_HOST" ] || [ -z "$ZVM_USER" ]; then
|
print_section "Extracting systemd components"
|
||||||
echo -e "${RED}Error: ZVM_HOST and ZVM_USER environment variables must be set${NC}"
|
|
||||||
echo ""
|
|
||||||
echo "Option 1: Create a .env file (recommended):"
|
|
||||||
echo " cp .env.example .env"
|
|
||||||
echo " # Edit .env with your z/VM details"
|
|
||||||
echo ""
|
|
||||||
echo "Option 2: Export variables manually:"
|
|
||||||
echo " export ZVM_HOST=your.zvm.host"
|
|
||||||
echo " export ZVM_USER=your_username"
|
|
||||||
echo " export ZVM_SSH_KEY='your-ssh-key-content'"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
ZVM_CONNECTION="${ZVM_USER}@${ZVM_HOST}"
|
|
||||||
ZVM_KEY="${ZVM_KEY:-zvm.pem}"
|
|
||||||
|
|
||||||
echo -e "${GREEN}=== Building systemd on z/VM RHEL 9.6 ===${NC}"
|
|
||||||
|
|
||||||
# Check if SSH key exists
|
|
||||||
if [ ! -f "$ZVM_KEY" ]; then
|
|
||||||
echo -e "${RED}Error: SSH key $ZVM_KEY not found${NC}"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# SSH options
|
|
||||||
SSH_OPTS="-i $ZVM_KEY -o StrictHostKeyChecking=${SSH_STRICT_HOST_KEY_CHECKING:-no} -o ConnectTimeout=${SSH_CONNECT_TIMEOUT:-10}"
|
|
||||||
|
|
||||||
# 1. Copy build script to z/VM
|
|
||||||
echo -e "${YELLOW}1. Copying build script to z/VM...${NC}"
|
|
||||||
scp $SSH_OPTS scripts/build-systemd-zvm.sh $ZVM_CONNECTION:~/
|
|
||||||
|
|
||||||
# 2. Run the build script
|
|
||||||
echo -e "${YELLOW}2. Running systemd build on z/VM (this may take 10-15 minutes)...${NC}"
|
|
||||||
ssh $SSH_OPTS $ZVM_CONNECTION "chmod +x ~/build-systemd-zvm.sh && ./build-systemd-zvm.sh"
|
|
||||||
|
|
||||||
# 3. Copy artifacts back with retry mechanism
|
|
||||||
echo -e "${YELLOW}3. Copying build artifacts back...${NC}"
|
|
||||||
mkdir -p output
|
|
||||||
|
|
||||||
# Function to copy with retries
|
|
||||||
copy_with_retry() {
|
|
||||||
local max_retries=5
|
|
||||||
local retry_count=0
|
|
||||||
local success=0
|
|
||||||
|
|
||||||
while [ $retry_count -lt $max_retries ] && [ $success -eq 0 ]; do
|
|
||||||
if [ $retry_count -gt 0 ]; then
|
|
||||||
echo -e "${YELLOW}Retry $retry_count/$max_retries - waiting 10 seconds before retrying...${NC}"
|
|
||||||
sleep 10
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Use timeout and compression options to handle stalls
|
|
||||||
if timeout 300 scp $SSH_OPTS -o ServerAliveInterval=15 -o ServerAliveCountMax=3 -C $ZVM_CONNECTION:~/systemd-minimal-s390x.tar.gz output/; then
|
|
||||||
success=1
|
|
||||||
echo -e "${GREEN}✓ Transfer completed successfully${NC}"
|
|
||||||
else
|
|
||||||
retry_count=$((retry_count + 1))
|
|
||||||
echo -e "${RED}Transfer failed or timed out${NC}"
|
|
||||||
|
|
||||||
# Kill any stalled scp processes
|
|
||||||
pkill -f "scp.*systemd-minimal-s390x.tar.gz" 2>/dev/null || true
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
if [ $success -eq 0 ]; then
|
|
||||||
echo -e "${RED}Failed to transfer after $max_retries attempts${NC}"
|
|
||||||
echo -e "${YELLOW}You can manually copy the file with:${NC}"
|
|
||||||
echo "scp $SSH_OPTS $ZVM_CONNECTION:~/systemd-minimal-s390x.tar.gz output/"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# Perform the copy with retries
|
|
||||||
copy_with_retry
|
|
||||||
|
|
||||||
# 4. Extract and organize
|
|
||||||
echo -e "${YELLOW}4. Extracting systemd...${NC}"
|
|
||||||
rm -rf output/systemd-root
|
rm -rf output/systemd-root
|
||||||
mkdir -p output/systemd-root
|
mkdir -p output/systemd-root
|
||||||
tar xzf output/systemd-minimal-s390x.tar.gz -C output/systemd-root
|
tar xzf output/systemd-minimal-s390x.tar.gz -C output/systemd-root
|
||||||
|
|
||||||
# 5. Report results
|
# Report results
|
||||||
echo -e "${GREEN}✓ Systemd built and extracted successfully!${NC}"
|
total_size=$(du -sh output/systemd-root 2>/dev/null | cut -f1)
|
||||||
TOTAL_SIZE=$(du -sh output/systemd-root 2>/dev/null | cut -f1)
|
log_success "Systemd built and extracted successfully!"
|
||||||
echo -e "${GREEN}Size: $TOTAL_SIZE${NC}"
|
log_info "Size: $total_size"
|
||||||
echo -e "${GREEN}Location: output/systemd-root/${NC}"
|
log_info "Location: output/systemd-root/"
|
||||||
|
|
||||||
# Show key files
|
# Show key files
|
||||||
echo -e "${YELLOW}Key systemd components:${NC}"
|
print_section "Key systemd components"
|
||||||
[ -f output/systemd-root/usr/lib/systemd/systemd ] && ls -lh output/systemd-root/usr/lib/systemd/systemd
|
if [ -f output/systemd-root/usr/lib/systemd/systemd ]; then
|
||||||
[ -f output/systemd-root/usr/lib/systemd/systemd-journald ] && ls -lh output/systemd-root/usr/lib/systemd/systemd-journald
|
ls -lh output/systemd-root/usr/lib/systemd/systemd
|
||||||
[ -f output/systemd-root/usr/lib/systemd/systemd-udevd ] && ls -lh output/systemd-root/usr/lib/systemd/systemd-udevd
|
else
|
||||||
[ -f output/systemd-root/usr/bin/systemctl ] && ls -lh output/systemd-root/usr/bin/systemctl
|
log_warning "systemd binary not found"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -f output/systemd-root/usr/lib/systemd/systemd-journald ]; then
|
||||||
|
ls -lh output/systemd-root/usr/lib/systemd/systemd-journald
|
||||||
|
else
|
||||||
|
log_warning "systemd-journald not found"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -f output/systemd-root/usr/lib/systemd/systemd-udevd ]; then
|
||||||
|
ls -lh output/systemd-root/usr/lib/systemd/systemd-udevd
|
||||||
|
else
|
||||||
|
log_warning "systemd-udevd not found"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -f output/systemd-root/usr/bin/systemctl ]; then
|
||||||
|
ls -lh output/systemd-root/usr/bin/systemctl
|
||||||
|
else
|
||||||
|
log_warning "systemctl not found"
|
||||||
|
fi
|
||||||
|
|
@ -1,24 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
# Complete s390x Arch Linux system running from initramfs only
|
|
||||||
|
|
||||||
# Get script directory and project root
|
|
||||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
||||||
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
|
|
||||||
|
|
||||||
echo "🚀 Starting Arch Linux s390x - Initramfs Only System"
|
|
||||||
echo "This will boot entirely from the initramfs (no separate root filesystem)"
|
|
||||||
echo "Press Ctrl-A X to exit"
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
cd "$PROJECT_ROOT"
|
|
||||||
|
|
||||||
qemu-system-s390x \
|
|
||||||
-machine s390-ccw-virtio \
|
|
||||||
-cpu max \
|
|
||||||
-m 2G \
|
|
||||||
-kernel "boot/vmlinuz-linux" \
|
|
||||||
-initrd "boot/initramfs-linux.img" \
|
|
||||||
-append "console=ttyS0 rdinit=/init" \
|
|
||||||
-nographic \
|
|
||||||
-device virtio-net-ccw,netdev=net0 \
|
|
||||||
-netdev user,id=net0
|
|
||||||
|
|
@ -1,192 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
# Test s390x Arch Linux with a root filesystem instead of just initramfs
|
|
||||||
|
|
||||||
# Get script directory and project root
|
|
||||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
||||||
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
|
|
||||||
|
|
||||||
echo "🚀 Starting Arch Linux s390x - Root Filesystem Test"
|
|
||||||
echo "This will boot with initramfs then switch to a root filesystem"
|
|
||||||
echo "Press Ctrl-A X to exit"
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
cd "$PROJECT_ROOT"
|
|
||||||
|
|
||||||
# Create a minimal root filesystem if it doesn't exist
|
|
||||||
ROOTFS_IMG="boot/rootfs-s390x.img"
|
|
||||||
|
|
||||||
# Force recreation of root filesystem to get updated init script
|
|
||||||
echo "Creating minimal root filesystem (forcing recreation)..."
|
|
||||||
rm -f "$ROOTFS_IMG"
|
|
||||||
|
|
||||||
# Create 150MB root filesystem image (for systemd)
|
|
||||||
dd if=/dev/zero of="$ROOTFS_IMG" bs=1M count=150
|
|
||||||
|
|
||||||
# Format as ext4
|
|
||||||
mkfs.ext4 -F "$ROOTFS_IMG"
|
|
||||||
|
|
||||||
# Mount and populate
|
|
||||||
mkdir -p /tmp/rootfs-mount
|
|
||||||
sudo mount -o loop "$ROOTFS_IMG" /tmp/rootfs-mount
|
|
||||||
|
|
||||||
# Create basic directory structure
|
|
||||||
sudo mkdir -p /tmp/rootfs-mount/{bin,sbin,etc,proc,sys,dev,tmp,var,usr/{bin,sbin},lib,lib64}
|
|
||||||
|
|
||||||
# Copy busybox as the main shell and utilities
|
|
||||||
sudo cp boot/busybox-s390x-static /tmp/rootfs-mount/bin/busybox
|
|
||||||
|
|
||||||
# Create busybox symlinks for basic utilities
|
|
||||||
sudo chroot /tmp/rootfs-mount /bin/busybox --install -s
|
|
||||||
|
|
||||||
# Copy systemd components if available
|
|
||||||
if [ -d "output/systemd-root" ]; then
|
|
||||||
echo "Installing systemd to root filesystem..."
|
|
||||||
sudo cp -r output/systemd-root/* /tmp/rootfs-mount/
|
|
||||||
|
|
||||||
# Create systemd init symlink
|
|
||||||
sudo ln -sf /usr/lib/systemd/systemd /tmp/rootfs-mount/sbin/init-systemd
|
|
||||||
|
|
||||||
# Create systemd directories
|
|
||||||
sudo mkdir -p /tmp/rootfs-mount/run/systemd
|
|
||||||
sudo mkdir -p /tmp/rootfs-mount/var/log/journal
|
|
||||||
sudo mkdir -p /tmp/rootfs-mount/etc/systemd/system
|
|
||||||
|
|
||||||
echo "✓ Systemd installed (42MB)"
|
|
||||||
else
|
|
||||||
echo "⚠ Systemd not found - using busybox init only"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Pre-create TTY devices to avoid errors
|
|
||||||
sudo mknod /tmp/rootfs-mount/dev/console c 5 1 2>/dev/null || true
|
|
||||||
sudo mknod /tmp/rootfs-mount/dev/tty c 5 0 2>/dev/null || true
|
|
||||||
sudo mknod /tmp/rootfs-mount/dev/tty1 c 4 1 2>/dev/null || true
|
|
||||||
sudo mknod /tmp/rootfs-mount/dev/tty2 c 4 2 2>/dev/null || true
|
|
||||||
sudo mknod /tmp/rootfs-mount/dev/tty3 c 4 3 2>/dev/null || true
|
|
||||||
sudo mknod /tmp/rootfs-mount/dev/tty4 c 4 4 2>/dev/null || true
|
|
||||||
|
|
||||||
# Create basic /etc/passwd
|
|
||||||
sudo tee /tmp/rootfs-mount/etc/passwd > /dev/null << 'EOF'
|
|
||||||
root:x:0:0:root:/root:/bin/sh
|
|
||||||
EOF
|
|
||||||
|
|
||||||
# Create basic /etc/group
|
|
||||||
sudo tee /tmp/rootfs-mount/etc/group > /dev/null << 'EOF'
|
|
||||||
root:x:0:
|
|
||||||
EOF
|
|
||||||
|
|
||||||
# Create /etc/os-release to identify as Arch Linux
|
|
||||||
sudo tee /tmp/rootfs-mount/etc/os-release > /dev/null << 'EOF'
|
|
||||||
NAME="Arch Linux"
|
|
||||||
PRETTY_NAME="Arch Linux"
|
|
||||||
ID=arch
|
|
||||||
BUILD_ID=rolling
|
|
||||||
ANSI_COLOR="38;2;23;147;209"
|
|
||||||
HOME_URL="https://archlinux.org/"
|
|
||||||
DOCUMENTATION_URL="https://wiki.archlinux.org/"
|
|
||||||
SUPPORT_URL="https://bbs.archlinux.org/"
|
|
||||||
BUG_REPORT_URL="https://bugs.archlinux.org/"
|
|
||||||
PRIVACY_POLICY_URL="https://terms.archlinux.org/docs/privacy-policy/"
|
|
||||||
LOGO=archlinux-logo
|
|
||||||
EOF
|
|
||||||
|
|
||||||
# Create /etc/arch-release (traditional Arch identifier)
|
|
||||||
sudo tee /tmp/rootfs-mount/etc/arch-release > /dev/null << 'EOF'
|
|
||||||
Arch Linux s390x \r (\l)
|
|
||||||
EOF
|
|
||||||
|
|
||||||
# Create /etc/hostname
|
|
||||||
sudo tee /tmp/rootfs-mount/etc/hostname > /dev/null << 'EOF'
|
|
||||||
archlinux-s390x
|
|
||||||
EOF
|
|
||||||
|
|
||||||
# Create basic /etc/hosts
|
|
||||||
sudo tee /tmp/rootfs-mount/etc/hosts > /dev/null << 'EOF'
|
|
||||||
127.0.0.1 localhost
|
|
||||||
::1 localhost
|
|
||||||
127.0.1.1 archlinux-s390x.localdomain archlinux-s390x
|
|
||||||
EOF
|
|
||||||
|
|
||||||
# Create basic init script for the root filesystem
|
|
||||||
sudo tee /tmp/rootfs-mount/sbin/init > /dev/null << 'EOF'
|
|
||||||
#!/bin/sh
|
|
||||||
echo "🎉 Welcome to Arch Linux s390x Root Filesystem!"
|
|
||||||
echo "This is running from a real root filesystem, not just initramfs."
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
# Mount essential filesystems
|
|
||||||
mount -t proc proc /proc 2>/dev/null || true
|
|
||||||
mount -t sysfs sysfs /sys 2>/dev/null || true
|
|
||||||
mount -t devtmpfs devtmpfs /dev 2>/dev/null || true
|
|
||||||
|
|
||||||
# Create TTY devices that busybox init expects
|
|
||||||
mknod /dev/tty1 c 4 1 2>/dev/null || true
|
|
||||||
mknod /dev/tty2 c 4 2 2>/dev/null || true
|
|
||||||
mknod /dev/tty3 c 4 3 2>/dev/null || true
|
|
||||||
mknod /dev/tty4 c 4 4 2>/dev/null || true
|
|
||||||
mknod /dev/console c 5 1 2>/dev/null || true
|
|
||||||
|
|
||||||
echo "=== ARCH LINUX VERIFICATION ==="
|
|
||||||
echo "Distribution info:"
|
|
||||||
if [ -f /etc/os-release ]; then
|
|
||||||
cat /etc/os-release
|
|
||||||
else
|
|
||||||
echo "No /etc/os-release found"
|
|
||||||
fi
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
if [ -f /etc/arch-release ]; then
|
|
||||||
echo "Arch release file:"
|
|
||||||
cat /etc/arch-release
|
|
||||||
else
|
|
||||||
echo "No /etc/arch-release found"
|
|
||||||
fi
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
echo "Hostname: $(cat /etc/hostname 2>/dev/null || echo 'Not set')"
|
|
||||||
echo "Architecture: $(uname -m)"
|
|
||||||
echo "Kernel: $(uname -r)"
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
echo "Root filesystem contents:"
|
|
||||||
ls -la /
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
echo "Available TTY devices:"
|
|
||||||
ls -la /dev/tty* 2>/dev/null || echo "No TTY devices found"
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
echo "Available commands:"
|
|
||||||
echo " ls, cat, mount, umount, ps, top, free, df, etc."
|
|
||||||
echo " Type 'busybox' to see all available applets"
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
echo "To verify this is Arch Linux, check:"
|
|
||||||
echo " cat /etc/os-release"
|
|
||||||
echo " cat /etc/arch-release"
|
|
||||||
echo " uname -a"
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
# Start a shell
|
|
||||||
exec /bin/sh
|
|
||||||
EOF
|
|
||||||
|
|
||||||
sudo chmod +x /tmp/rootfs-mount/sbin/init
|
|
||||||
|
|
||||||
sudo umount /tmp/rootfs-mount
|
|
||||||
rmdir /tmp/rootfs-mount
|
|
||||||
|
|
||||||
echo "✅ Root filesystem created at $ROOTFS_IMG"
|
|
||||||
|
|
||||||
# Boot with root filesystem
|
|
||||||
qemu-system-s390x \
|
|
||||||
-machine s390-ccw-virtio \
|
|
||||||
-cpu max \
|
|
||||||
-m 2G \
|
|
||||||
-kernel "boot/vmlinuz-linux" \
|
|
||||||
-initrd "boot/initramfs-linux.img" \
|
|
||||||
-append "console=ttyS0 root=/dev/vda rw init=/sbin/init" \
|
|
||||||
-drive file="$ROOTFS_IMG",format=raw,if=none,id=rootdisk \
|
|
||||||
-device virtio-blk-ccw,drive=rootdisk \
|
|
||||||
-nographic \
|
|
||||||
-device virtio-net-ccw,netdev=net0 \
|
|
||||||
-netdev user,id=net0
|
|
||||||
|
|
@ -1,102 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
# Test s390x Arch Linux with systemd as init
|
|
||||||
|
|
||||||
# Get script directory and project root
|
|
||||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
||||||
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
|
|
||||||
|
|
||||||
echo "🚀 Starting Arch Linux s390x - Systemd Test"
|
|
||||||
echo "This will boot with systemd as PID 1"
|
|
||||||
echo "Press Ctrl-A X to exit"
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
cd "$PROJECT_ROOT"
|
|
||||||
|
|
||||||
# Check if systemd is available
|
|
||||||
if [ ! -d "output/systemd-root" ]; then
|
|
||||||
echo "Error: Systemd not found. Run 'make systemd' first"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Create systemd-enabled root filesystem directly
|
|
||||||
echo "Preparing systemd-enabled root filesystem..."
|
|
||||||
|
|
||||||
ROOTFS_IMG="boot/rootfs-s390x.img"
|
|
||||||
|
|
||||||
# Force recreation of root filesystem
|
|
||||||
rm -f "$ROOTFS_IMG"
|
|
||||||
|
|
||||||
# Create 150MB root filesystem image (for systemd)
|
|
||||||
dd if=/dev/zero of="$ROOTFS_IMG" bs=1M count=150
|
|
||||||
|
|
||||||
# Format as ext4
|
|
||||||
mkfs.ext4 -F "$ROOTFS_IMG"
|
|
||||||
|
|
||||||
# Mount and populate
|
|
||||||
mkdir -p /tmp/rootfs-mount
|
|
||||||
sudo mount -o loop "$ROOTFS_IMG" /tmp/rootfs-mount
|
|
||||||
|
|
||||||
# Create basic directory structure
|
|
||||||
sudo mkdir -p /tmp/rootfs-mount/{bin,sbin,etc,proc,sys,dev,tmp,var,usr/{bin,sbin},lib,lib64}
|
|
||||||
|
|
||||||
# Copy busybox as fallback
|
|
||||||
sudo cp boot/busybox-s390x-static /tmp/rootfs-mount/bin/busybox
|
|
||||||
sudo chroot /tmp/rootfs-mount /bin/busybox --install -s
|
|
||||||
|
|
||||||
# Install systemd
|
|
||||||
echo "Installing systemd to root filesystem..."
|
|
||||||
sudo cp -r output/systemd-root/* /tmp/rootfs-mount/
|
|
||||||
|
|
||||||
# Create systemd directories
|
|
||||||
sudo mkdir -p /tmp/rootfs-mount/run/systemd
|
|
||||||
sudo mkdir -p /tmp/rootfs-mount/var/log/journal
|
|
||||||
sudo mkdir -p /tmp/rootfs-mount/etc/systemd/system
|
|
||||||
sudo mkdir -p /tmp/rootfs-mount/sys
|
|
||||||
sudo mkdir -p /tmp/rootfs-mount/proc
|
|
||||||
|
|
||||||
# Create device nodes
|
|
||||||
sudo mknod /tmp/rootfs-mount/dev/console c 5 1 2>/dev/null || true
|
|
||||||
sudo mknod /tmp/rootfs-mount/dev/tty c 5 0 2>/dev/null || true
|
|
||||||
sudo mknod /tmp/rootfs-mount/dev/tty1 c 4 1 2>/dev/null || true
|
|
||||||
|
|
||||||
# Create basic files
|
|
||||||
sudo tee /tmp/rootfs-mount/etc/passwd > /dev/null << 'EOF'
|
|
||||||
root:x:0:0:root:/root:/bin/sh
|
|
||||||
EOF
|
|
||||||
|
|
||||||
sudo tee /tmp/rootfs-mount/etc/group > /dev/null << 'EOF'
|
|
||||||
root:x:0:
|
|
||||||
EOF
|
|
||||||
|
|
||||||
sudo tee /tmp/rootfs-mount/etc/os-release > /dev/null << 'EOF'
|
|
||||||
NAME="Arch Linux"
|
|
||||||
PRETTY_NAME="Arch Linux"
|
|
||||||
ID=arch
|
|
||||||
BUILD_ID=rolling
|
|
||||||
EOF
|
|
||||||
|
|
||||||
sudo tee /tmp/rootfs-mount/etc/hostname > /dev/null << 'EOF'
|
|
||||||
archlinux-s390x
|
|
||||||
EOF
|
|
||||||
|
|
||||||
# Unmount
|
|
||||||
sudo umount /tmp/rootfs-mount
|
|
||||||
rmdir /tmp/rootfs-mount
|
|
||||||
|
|
||||||
echo "✓ Root filesystem with systemd prepared"
|
|
||||||
|
|
||||||
# Run QEMU with systemd as init
|
|
||||||
echo "Booting with systemd..."
|
|
||||||
qemu-system-s390x \
|
|
||||||
-M s390-ccw-virtio \
|
|
||||||
-cpu qemu \
|
|
||||||
-m 2G \
|
|
||||||
-smp 1 \
|
|
||||||
-kernel boot/vmlinuz-linux \
|
|
||||||
-initrd boot/initramfs-linux.img \
|
|
||||||
-append "console=ttyS0 root=/dev/vda rw init=/usr/lib/systemd/systemd systemd.log_level=debug" \
|
|
||||||
-drive file=boot/rootfs-s390x.img,format=raw,if=virtio \
|
|
||||||
-netdev user,id=network0 \
|
|
||||||
-device virtio-net,netdev=network0 \
|
|
||||||
-nographic \
|
|
||||||
-serial mon:stdio
|
|
||||||
174
scripts/test-qemu.sh
Executable file
174
scripts/test-qemu.sh
Executable file
|
|
@ -0,0 +1,174 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# Unified QEMU testing script for Arch Linux s390x
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
|
||||||
|
# Source utilities
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
source "$SCRIPT_DIR/common.sh"
|
||||||
|
source "$SCRIPT_DIR/create-rootfs.sh"
|
||||||
|
|
||||||
|
# Test configuration
|
||||||
|
TEST_MODE="${1:-initramfs}"
|
||||||
|
ROOTFS_SIZE="${2:-150}"
|
||||||
|
|
||||||
|
# Initialize
|
||||||
|
init_common
|
||||||
|
|
||||||
|
# Change to project root
|
||||||
|
cd "$PROJECT_ROOT"
|
||||||
|
|
||||||
|
# Validate boot files exist
|
||||||
|
check_required_files "boot/vmlinuz-linux" "boot/initramfs-linux.img"
|
||||||
|
|
||||||
|
# Test functions
|
||||||
|
test_initramfs_only() {
|
||||||
|
print_header "Testing Arch Linux s390x - Initramfs Only"
|
||||||
|
|
||||||
|
log_info "Starting QEMU with initramfs-only boot..."
|
||||||
|
log_info "This will boot into the initramfs environment with busybox shell"
|
||||||
|
log_info "Press Ctrl-A X to exit QEMU"
|
||||||
|
echo
|
||||||
|
|
||||||
|
run_qemu_s390x "rdinit=/init"
|
||||||
|
}
|
||||||
|
|
||||||
|
test_rootfs_boot() {
|
||||||
|
print_header "Testing Arch Linux s390x - Root Filesystem"
|
||||||
|
|
||||||
|
local rootfs_img="boot/rootfs-s390x.img"
|
||||||
|
|
||||||
|
# Create root filesystem if it doesn't exist or is older than busybox
|
||||||
|
if [ ! -f "$rootfs_img" ] || [ "boot/busybox-s390x-static" -nt "$rootfs_img" ]; then
|
||||||
|
log_info "Creating root filesystem..."
|
||||||
|
create_busybox_rootfs "$rootfs_img" "$ROOTFS_SIZE"
|
||||||
|
else
|
||||||
|
log_info "Using existing root filesystem: $rootfs_img"
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_info "Starting QEMU with root filesystem switching..."
|
||||||
|
log_info "This will boot from initramfs, then switch to root filesystem"
|
||||||
|
log_info "Expected: Arch Linux identification and busybox shell on root filesystem"
|
||||||
|
log_info "Press Ctrl-A X to exit QEMU"
|
||||||
|
echo
|
||||||
|
|
||||||
|
run_qemu_s390x "root=/dev/vda rw init=/sbin/init" \
|
||||||
|
"-drive file=$rootfs_img,format=raw,if=none,id=rootdisk -device virtio-blk-ccw,drive=rootdisk"
|
||||||
|
}
|
||||||
|
|
||||||
|
test_systemd_boot() {
|
||||||
|
print_header "Testing Arch Linux s390x - Systemd"
|
||||||
|
|
||||||
|
local rootfs_img="boot/rootfs-s390x.img"
|
||||||
|
|
||||||
|
# Check if systemd is available
|
||||||
|
if [ ! -d "output/systemd-root" ]; then
|
||||||
|
die "Systemd not found. Run 'make systemd' first to build systemd components"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create systemd root filesystem
|
||||||
|
log_info "Creating systemd root filesystem..."
|
||||||
|
create_systemd_rootfs "$rootfs_img" "$ROOTFS_SIZE"
|
||||||
|
|
||||||
|
log_info "Starting QEMU with systemd as init..."
|
||||||
|
log_info "This will boot with systemd as PID 1"
|
||||||
|
log_info "Expected: 'Welcome to Arch Linux!' and systemd boot sequence"
|
||||||
|
log_info "Press Ctrl-A X to exit QEMU"
|
||||||
|
echo
|
||||||
|
|
||||||
|
run_qemu_s390x "root=/dev/vda rw init=/usr/lib/systemd/systemd systemd.log_level=debug" \
|
||||||
|
"-drive file=$rootfs_img,format=raw,if=virtio -serial mon:stdio"
|
||||||
|
}
|
||||||
|
|
||||||
|
test_qemu_info() {
|
||||||
|
print_header "QEMU System Information"
|
||||||
|
|
||||||
|
log_info "QEMU s390x version:"
|
||||||
|
qemu-system-s390x --version || log_warning "QEMU s390x not found"
|
||||||
|
|
||||||
|
echo
|
||||||
|
log_info "Available s390x machines:"
|
||||||
|
qemu-system-s390x -machine help | grep s390 || true
|
||||||
|
|
||||||
|
echo
|
||||||
|
log_info "Boot files status:"
|
||||||
|
if [ -f "boot/vmlinuz-linux" ]; then
|
||||||
|
local kernel_size=$(get_file_size "boot/vmlinuz-linux")
|
||||||
|
log_success "Kernel: boot/vmlinuz-linux ($kernel_size)"
|
||||||
|
else
|
||||||
|
log_error "Kernel: boot/vmlinuz-linux (missing)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -f "boot/initramfs-linux.img" ]; then
|
||||||
|
local initramfs_size=$(get_file_size "boot/initramfs-linux.img")
|
||||||
|
log_success "Initramfs: boot/initramfs-linux.img ($initramfs_size)"
|
||||||
|
else
|
||||||
|
log_error "Initramfs: boot/initramfs-linux.img (missing)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -f "boot/rootfs-s390x.img" ]; then
|
||||||
|
local rootfs_size=$(get_file_size "boot/rootfs-s390x.img")
|
||||||
|
log_success "Root filesystem: boot/rootfs-s390x.img ($rootfs_size)"
|
||||||
|
else
|
||||||
|
log_info "Root filesystem: boot/rootfs-s390x.img (will be created)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo
|
||||||
|
log_info "Systemd availability:"
|
||||||
|
if [ -d "output/systemd-root" ]; then
|
||||||
|
log_success "Systemd: Available in output/systemd-root"
|
||||||
|
else
|
||||||
|
log_warning "Systemd: Not available (run 'make systemd' to build)"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
show_usage() {
|
||||||
|
cat << EOF
|
||||||
|
Usage: $0 [MODE] [ROOTFS_SIZE]
|
||||||
|
|
||||||
|
MODES:
|
||||||
|
initramfs Test initramfs-only system (default)
|
||||||
|
rootfs Test with root filesystem switching
|
||||||
|
systemd Test with systemd as init system
|
||||||
|
info Show system information and file status
|
||||||
|
|
||||||
|
ROOTFS_SIZE:
|
||||||
|
Size in MB for root filesystem creation (default: 150)
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
$0 # Test initramfs-only (default)
|
||||||
|
$0 rootfs # Test root filesystem with default size
|
||||||
|
$0 systemd 200 # Test systemd with 200MB root filesystem
|
||||||
|
$0 info # Show system information
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
- All tests require boot/vmlinuz-linux and boot/initramfs-linux.img
|
||||||
|
- Systemd test requires 'make systemd' to be run first
|
||||||
|
- Root filesystem will be created automatically if needed
|
||||||
|
- Press Ctrl-A X to exit QEMU during testing
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
# Main execution
|
||||||
|
case "$TEST_MODE" in
|
||||||
|
"initramfs"|"initramfs-only")
|
||||||
|
test_initramfs_only
|
||||||
|
;;
|
||||||
|
"rootfs"|"root"|"filesystem")
|
||||||
|
test_rootfs_boot
|
||||||
|
;;
|
||||||
|
"systemd"|"systemd-boot")
|
||||||
|
test_systemd_boot
|
||||||
|
;;
|
||||||
|
"info"|"status")
|
||||||
|
test_qemu_info
|
||||||
|
;;
|
||||||
|
"help"|"-h"|"--help")
|
||||||
|
show_usage
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
log_error "Unknown test mode: $TEST_MODE"
|
||||||
|
echo
|
||||||
|
show_usage
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
260
scripts/zvm-utils.sh
Normal file
260
scripts/zvm-utils.sh
Normal file
|
|
@ -0,0 +1,260 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# z/VM connection and build utilities for Arch Linux s390x
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
|
||||||
|
# Source common utilities
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
source "$SCRIPT_DIR/common.sh"
|
||||||
|
|
||||||
|
# z/VM Configuration defaults
|
||||||
|
export ZVM_KEY="${ZVM_KEY:-zvm.pem}"
|
||||||
|
export SSH_CONNECT_TIMEOUT="${SSH_CONNECT_TIMEOUT:-10}"
|
||||||
|
export SSH_STRICT_HOST_KEY_CHECKING="${SSH_STRICT_HOST_KEY_CHECKING:-no}"
|
||||||
|
export SSH_SERVER_ALIVE_INTERVAL="${SSH_SERVER_ALIVE_INTERVAL:-15}"
|
||||||
|
export SSH_SERVER_ALIVE_COUNT_MAX="${SSH_SERVER_ALIVE_COUNT_MAX:-3}"
|
||||||
|
export SCP_TIMEOUT="${SCP_TIMEOUT:-300}"
|
||||||
|
export RETRY_MAX_ATTEMPTS="${RETRY_MAX_ATTEMPTS:-5}"
|
||||||
|
export RETRY_DELAY="${RETRY_DELAY:-10}"
|
||||||
|
|
||||||
|
# Load z/VM environment variables
|
||||||
|
load_zvm_env() {
|
||||||
|
log_debug "Loading z/VM environment..."
|
||||||
|
|
||||||
|
# Try to load from .env if variables aren't set
|
||||||
|
if [ -z "${ZVM_HOST:-}" ] || [ -z "${ZVM_USER:-}" ]; then
|
||||||
|
if [ -f ".env" ]; then
|
||||||
|
log_info "Loading z/VM configuration from .env file..."
|
||||||
|
load_env ".env"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Validate required variables
|
||||||
|
if [ -z "${ZVM_HOST:-}" ]; then
|
||||||
|
die "ZVM_HOST environment variable must be set"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "${ZVM_USER:-}" ]; then
|
||||||
|
die "ZVM_USER environment variable must be set"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Set up derived variables
|
||||||
|
export ZVM_CONNECTION="${ZVM_USER}@${ZVM_HOST}"
|
||||||
|
export SSH_OPTS="-i $ZVM_KEY -o StrictHostKeyChecking=$SSH_STRICT_HOST_KEY_CHECKING -o ConnectTimeout=$SSH_CONNECT_TIMEOUT -o ServerAliveInterval=$SSH_SERVER_ALIVE_INTERVAL -o ServerAliveCountMax=$SSH_SERVER_ALIVE_COUNT_MAX"
|
||||||
|
|
||||||
|
log_debug "z/VM connection: $ZVM_CONNECTION"
|
||||||
|
log_debug "SSH options: $SSH_OPTS"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Setup SSH key for z/VM access
|
||||||
|
setup_zvm_ssh_key() {
|
||||||
|
if [ -n "${ZVM_SSH_KEY:-}" ] && [ ! -f "$ZVM_KEY" ]; then
|
||||||
|
log_info "Setting up SSH key for z/VM access..."
|
||||||
|
echo "$ZVM_SSH_KEY" > "$ZVM_KEY"
|
||||||
|
chmod 600 "$ZVM_KEY"
|
||||||
|
log_success "SSH key created: $ZVM_KEY"
|
||||||
|
elif [ ! -f "$ZVM_KEY" ]; then
|
||||||
|
die "SSH key not found: $ZVM_KEY. Set ZVM_SSH_KEY environment variable or create the key file."
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Test z/VM connection
|
||||||
|
test_zvm_connection() {
|
||||||
|
log_info "Testing z/VM connection..."
|
||||||
|
|
||||||
|
if ssh $SSH_OPTS "$ZVM_CONNECTION" "echo 'Connection successful'" >/dev/null 2>&1; then
|
||||||
|
log_success "z/VM connection test passed"
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
log_error "z/VM connection test failed"
|
||||||
|
log_error "Check your SSH key, hostname, and network connectivity"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Copy file to z/VM with retry mechanism
|
||||||
|
copy_to_zvm() {
|
||||||
|
local source_file="$1"
|
||||||
|
local dest_path="${2:-~/}"
|
||||||
|
local max_retries="${3:-$RETRY_MAX_ATTEMPTS}"
|
||||||
|
|
||||||
|
log_info "Copying $source_file to z/VM:$dest_path"
|
||||||
|
|
||||||
|
if [ ! -f "$source_file" ]; then
|
||||||
|
die "Source file not found: $source_file"
|
||||||
|
fi
|
||||||
|
|
||||||
|
local retry_count=0
|
||||||
|
local success=0
|
||||||
|
|
||||||
|
while [ $retry_count -lt $max_retries ] && [ $success -eq 0 ]; do
|
||||||
|
if [ $retry_count -gt 0 ]; then
|
||||||
|
log_warning "Retry $retry_count/$max_retries - waiting ${RETRY_DELAY} seconds..."
|
||||||
|
sleep "$RETRY_DELAY"
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_debug "Attempt $((retry_count + 1)): scp $source_file to $ZVM_CONNECTION:$dest_path"
|
||||||
|
|
||||||
|
# Use timeout and compression options to handle stalls
|
||||||
|
if timeout "$SCP_TIMEOUT" scp $SSH_OPTS -C "$source_file" "$ZVM_CONNECTION:$dest_path"; then
|
||||||
|
success=1
|
||||||
|
log_success "Transfer completed successfully"
|
||||||
|
else
|
||||||
|
retry_count=$((retry_count + 1))
|
||||||
|
log_error "Transfer failed or timed out"
|
||||||
|
|
||||||
|
# Kill any stalled scp processes
|
||||||
|
pkill -f "scp.*$(basename "$source_file")" 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ $success -eq 0 ]; then
|
||||||
|
die "Failed to transfer $source_file after $max_retries attempts"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Copy file from z/VM with retry mechanism
|
||||||
|
copy_from_zvm() {
|
||||||
|
local source_path="$1"
|
||||||
|
local dest_file="$2"
|
||||||
|
local max_retries="${3:-$RETRY_MAX_ATTEMPTS}"
|
||||||
|
|
||||||
|
log_info "Copying z/VM:$source_path to $dest_file"
|
||||||
|
|
||||||
|
local retry_count=0
|
||||||
|
local success=0
|
||||||
|
|
||||||
|
while [ $retry_count -lt $max_retries ] && [ $success -eq 0 ]; do
|
||||||
|
if [ $retry_count -gt 0 ]; then
|
||||||
|
log_warning "Retry $retry_count/$max_retries - waiting ${RETRY_DELAY} seconds..."
|
||||||
|
sleep "$RETRY_DELAY"
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_debug "Attempt $((retry_count + 1)): scp from $ZVM_CONNECTION:$source_path"
|
||||||
|
|
||||||
|
# Use timeout and compression options to handle stalls
|
||||||
|
if timeout "$SCP_TIMEOUT" scp $SSH_OPTS -C "$ZVM_CONNECTION:$source_path" "$dest_file"; then
|
||||||
|
success=1
|
||||||
|
log_success "Transfer completed successfully"
|
||||||
|
else
|
||||||
|
retry_count=$((retry_count + 1))
|
||||||
|
log_error "Transfer failed or timed out"
|
||||||
|
|
||||||
|
# Kill any stalled scp processes
|
||||||
|
pkill -f "scp.*$(basename "$source_path")" 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ $success -eq 0 ]; then
|
||||||
|
die "Failed to transfer $source_path after $max_retries attempts"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Execute command on z/VM
|
||||||
|
execute_on_zvm() {
|
||||||
|
local command="$1"
|
||||||
|
local timeout_duration="${2:-600}"
|
||||||
|
|
||||||
|
log_info "Executing on z/VM: $command"
|
||||||
|
|
||||||
|
if timeout "$timeout_duration" ssh $SSH_OPTS "$ZVM_CONNECTION" "$command"; then
|
||||||
|
log_success "Command executed successfully"
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
log_error "Command failed or timed out: $command"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Execute script on z/VM
|
||||||
|
execute_script_on_zvm() {
|
||||||
|
local script_path="$1"
|
||||||
|
local remote_path="${2:-~/$(basename "$script_path")}"
|
||||||
|
local timeout_duration="${3:-600}"
|
||||||
|
|
||||||
|
log_info "Executing script $script_path on z/VM"
|
||||||
|
|
||||||
|
# Copy script to z/VM
|
||||||
|
copy_to_zvm "$script_path" "$remote_path"
|
||||||
|
|
||||||
|
# Make it executable and run it
|
||||||
|
execute_on_zvm "chmod +x $remote_path && $remote_path" "$timeout_duration"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Build component on z/VM using a build script
|
||||||
|
build_on_zvm() {
|
||||||
|
local component_name="$1"
|
||||||
|
local build_script="$2"
|
||||||
|
local output_archive="${3:-${component_name}-s390x.tar.gz}"
|
||||||
|
local timeout_duration="${4:-1800}"
|
||||||
|
|
||||||
|
print_section "Building $component_name on z/VM"
|
||||||
|
|
||||||
|
start_timer
|
||||||
|
|
||||||
|
# Test connection first
|
||||||
|
test_zvm_connection || die "Cannot connect to z/VM"
|
||||||
|
|
||||||
|
# Execute build script
|
||||||
|
log_info "Running build script: $build_script"
|
||||||
|
execute_script_on_zvm "$build_script" "~/build-${component_name}.sh" "$timeout_duration"
|
||||||
|
|
||||||
|
# Copy back the results
|
||||||
|
if [ -n "$output_archive" ]; then
|
||||||
|
log_info "Copying build artifacts..."
|
||||||
|
ensure_dir "$OUTPUT_DIR"
|
||||||
|
copy_from_zvm "~/$output_archive" "$OUTPUT_DIR/$output_archive"
|
||||||
|
|
||||||
|
if [ -f "$OUTPUT_DIR/$output_archive" ]; then
|
||||||
|
local size=$(get_file_size "$OUTPUT_DIR/$output_archive")
|
||||||
|
log_success "$component_name build completed - $size archive created"
|
||||||
|
else
|
||||||
|
die "Build artifact not found: $OUTPUT_DIR/$output_archive"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
end_timer
|
||||||
|
}
|
||||||
|
|
||||||
|
# Initialize z/VM utilities
|
||||||
|
init_zvm() {
|
||||||
|
# Initialize common environment first
|
||||||
|
init_common
|
||||||
|
|
||||||
|
# Load z/VM specific environment
|
||||||
|
load_zvm_env
|
||||||
|
|
||||||
|
# Setup SSH key
|
||||||
|
setup_zvm_ssh_key
|
||||||
|
|
||||||
|
log_debug "z/VM utilities initialized"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Clean up z/VM build artifacts
|
||||||
|
cleanup_zvm_build() {
|
||||||
|
local component_name="$1"
|
||||||
|
local artifacts="${2:-${component_name}-s390x.tar.gz build-${component_name}.sh}"
|
||||||
|
|
||||||
|
log_info "Cleaning up z/VM build artifacts for $component_name"
|
||||||
|
|
||||||
|
for artifact in $artifacts; do
|
||||||
|
execute_on_zvm "rm -f ~/$artifact" || log_warning "Failed to remove $artifact"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
# Show z/VM system information
|
||||||
|
show_zvm_info() {
|
||||||
|
log_info "Gathering z/VM system information..."
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo -e "${CYAN}=== z/VM System Information ===${NC}"
|
||||||
|
execute_on_zvm "uname -a" || true
|
||||||
|
execute_on_zvm "cat /etc/os-release" || true
|
||||||
|
execute_on_zvm "df -h ~" || true
|
||||||
|
execute_on_zvm "free -h" || true
|
||||||
|
echo
|
||||||
|
}
|
||||||
|
|
||||||
|
# Export functions for use in other scripts
|
||||||
|
export -f load_zvm_env setup_zvm_ssh_key test_zvm_connection
|
||||||
|
export -f copy_to_zvm copy_from_zvm execute_on_zvm execute_script_on_zvm
|
||||||
|
export -f build_on_zvm init_zvm cleanup_zvm_build show_zvm_info
|
||||||
Loading…
Reference in a new issue