I needed to convert a basestrapped dinit install; on a headless server with multiple raid1 partitions (hence the conversion vs reinstall), to openrc(Why, you ask? Cause k3s install script supports openrc, out da box!).
I started following the wiki article on converting the init system, but ran into some issues with updated package naming conventions for openrc.
$ pacman -Sw $(sed 's/openrc/s6/g' < services.list)
error: target not found: openrc-init
[ERROR] Failed to download core OpenRC packages
Turns out OpenRC itself provides the init functionality - beginning with OpenRC 0.25, it replaced /sbin/init with its own program. In Artix, the core OpenRC package is simply called openrc.
So I headed over to claude4(Why on earth!?!, While I am an accomplished sysadmin, frontend sass, css, html, advanced drupal ui dude, I'm new to coding, well... other than by the seat of my pant's, skin of my teeth sutuations where I have to hack php to unbreakerate things.) Anyway, I passed on what I tried and, after overcoming a few issues, ended up with the following script.
Disclaimer:
Use at your own risk. Could break stuff. If you choose to use this weapon on your quest, it's on you. 
#!/bin/bash
# Artix Linux: Dinit to OpenRC Migration Script
# Run this from a live CD environment with the target system chrooted
set -e # Exit on any error
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Logging function
log() {
echo -e "${BLUE}[$(date '+%Y-%m-%d %H:%M:%S')]${NC} $1"
}
error() {
echo -e "${RED}[ERROR]${NC} $1" >&2
}
warning() {
echo -e "${YELLOW}[WARNING]${NC} $1"
}
success() {
echo -e "${GREEN}[SUCCESS]${NC} $1"
}
# Check if we're in a chroot environment
check_chroot() {
if [[ "$(stat -c %d:%i /)" != "$(stat -c %d:%i /proc/1/root/.)" ]]; then
log "Running in chroot environment ✓"
else
error "This script should be run from a chroot environment (live CD)"
exit 1
fi
}
# Check current init system status
check_init_system() {
local has_dinit=$(pacman -Qs dinit 2>/dev/null | wc -l)
local has_openrc=$(pacman -Qs openrc 2>/dev/null | wc -l)
if [[ $has_dinit -gt 0 && $has_openrc -eq 0 ]]; then
log "Dinit system detected, proceeding with migration ✓"
return 0
elif [[ $has_dinit -eq 0 && $has_openrc -gt 0 ]]; then
log "OpenRC system detected, checking migration status..."
check_migration_success
return 1
elif [[ $has_dinit -gt 0 && $has_openrc -gt 0 ]]; then
warning "Both dinit and OpenRC packages found - partial migration detected"
log "Continuing with migration cleanup..."
return 0
else
error "No recognized init system found (neither dinit nor OpenRC)"
exit 1
fi
}
# Check if migration was successful
check_migration_success() {
log "Checking OpenRC migration status..."
# Check if OpenRC is installed
if ! pacman -Qs openrc > /dev/null 2>&1; then
error "OpenRC not found - migration incomplete"
return 1
fi
# Check if dinit packages are removed
local remaining_dinit=$(pacman -Qs dinit 2>/dev/null | wc -l)
if [[ $remaining_dinit -gt 0 ]]; then
warning "Some dinit packages still present:"
pacman -Qs dinit
log "You may need to remove these manually"
else
success "All dinit packages removed ✓"
fi
# Check if essential OpenRC services are configured
local configured_services=0
local essential_services=("hostname" "networking" "hwclock" "modules" "localmount")
for service in "${essential_services[@]}"; do
if rc-update show | grep -q "$service"; then
((configured_services++))
fi
done
if [[ $configured_services -gt 0 ]]; then
success "OpenRC services configured ($configured_services essential services found) ✓"
else
warning "No essential OpenRC services appear to be configured"
fi
# Check if OpenRC can manage services
if command -v rc-service >/dev/null 2>&1; then
success "OpenRC service management available ✓"
else
error "OpenRC service management not available"
return 1
fi
# Overall status
if [[ $remaining_dinit -eq 0 && $configured_services -gt 0 ]]; then
success "Migration appears successful! ✓"
log "System should boot with OpenRC after reboot"
return 0
else
warning "Migration may be incomplete - manual intervention might be needed"
return 1
fi
}
# Backup current dinit services
backup_services() {
log "Backing up current dinit services..."
# Get dinit packages
pacman -Qsq dinit > services.list 2>/dev/null || {
error "Failed to query dinit packages"
exit 1
}
# Also backup enabled services if possible
if [ -d /etc/dinit.d ]; then
find /etc/dinit.d -name "*.d" -type d > enabled_services.list 2>/dev/null || true
fi
local service_count=$(wc -l < services.list)
success "Backed up $service_count dinit packages to services.list"
}
# Download OpenRC packages
download_openrc_packages() {
log "Downloading OpenRC packages..."
# Convert dinit package names to openrc equivalents
# This sed command replaces 'dinit' with 'openrc' in package names
local openrc_packages=$(sed 's/dinit/openrc/g' < services.list)
# Create a temporary file to check which packages exist
echo "$openrc_packages" > openrc_packages.list
# Download essential OpenRC packages first
local essential_packages="openrc elogind-openrc"
log "Downloading essential OpenRC packages: $essential_packages"
if pacman -Sw --noconfirm $essential_packages; then
success "Downloaded essential OpenRC packages"
else
error "Failed to download essential OpenRC packages"
exit 1
fi
# Download packages (this doesn't install them)
log "Attempting to download OpenRC service packages..."
local failed_packages=""
while IFS= read -r package; do
if [[ -n "$package" && "$package" != "openrc" ]]; then
if pacman -Sw --noconfirm "$package" 2>/dev/null; then
log "Downloaded: $package"
else
failed_packages="$failed_packages $package"
warning "Could not download: $package"
fi
fi
done < openrc_packages.list
if [[ -n "$failed_packages" ]]; then
warning "Some packages couldn't be downloaded:$failed_packages"
log "These may not exist or have different names in OpenRC"
fi
}
# Remove dinit packages
remove_dinit() {
log "Removing dinit packages..."
# Use -Rdd to remove without checking dependencies
# This is necessary because we're replacing the init system
if pacman -Rdd --noconfirm $(cat services.list); then
success "Successfully removed dinit packages"
else
error "Failed to remove dinit packages"
exit 1
fi
}
# Install OpenRC
install_openrc() {
log "Installing OpenRC..."
# Install core OpenRC and elogind (session management)
local core_packages="openrc elogind-openrc"
if pacman -S --noconfirm $core_packages; then
success "Installed core OpenRC packages: $core_packages"
else
error "Failed to install core OpenRC packages"
exit 1
fi
# Try to install service equivalents
log "Installing OpenRC service packages..."
local openrc_packages=$(sed 's/dinit/openrc/g' < services.list)
# Install packages one by one, skipping failures
local installed_count=0
local failed_count=0
while IFS= read -r package; do
if [[ -n "$package" && "$package" != "openrc" && "$package" != "elogind-openrc" ]]; then
if pacman -S --noconfirm "$package" 2>/dev/null; then
log "Installed: $package"
((installed_count++))
else
warning "Could not install: $package (may not exist or have different name)"
((failed_count++))
fi
fi
done < openrc_packages.list
success "Installed $installed_count OpenRC service packages ($failed_count failed)"
}
# Configure OpenRC services
configure_services() {
log "Configuring OpenRC services..."
# Suppress OpenRC help output by redirecting stderr
export RC_QUIET=1
# Enable essential services for boot runlevel
local boot_services=(
"hwclock"
"modules"
"fsck"
"root"
"localmount"
"swap"
"urandom"
)
for service in "${boot_services[@]}"; do
if [ -f "/etc/init.d/$service" ]; then
if rc-update add "$service" boot >/dev/null 2>&1; then
log "Enabled boot service: $service"
else
warning "Could not enable boot service: $service"
fi
fi
done
# Enable essential services for default runlevel
local default_services=(
"hostname"
"networking"
"elogind"
"local"
"netmount"
)
for service in "${default_services[@]}"; do
if [ -f "/etc/init.d/$service" ]; then
if rc-update add "$service" default >/dev/null 2>&1; then
log "Enabled default service: $service"
else
warning "Could not enable default service: $service"
fi
fi
done
# Add localmount to default runlevel as required by OpenRC 0.62.2
if [ -f "/etc/init.d/localmount" ]; then
rc-update add localmount default >/dev/null 2>&1 || true
fi
success "OpenRC services configured"
# Show runlevel status (suppress help output)
log "Current runlevel configuration:"
rc-update show 2>/dev/null || log "Could not display runlevel status"
}
# Update bootloader if needed
update_bootloader() {
log "Checking bootloader configuration..."
# Check if using GRUB
if [ -f "/boot/grub/grub.cfg" ]; then
log "GRUB detected, updating configuration..."
if command -v grub-mkconfig >/dev/null 2>&1; then
grub-mkconfig -o /boot/grub/grub.cfg
success "Updated GRUB configuration"
else
warning "grub-mkconfig not found, you may need to update bootloader manually"
fi
fi
# Check for other bootloaders
if [ -f "/boot/loader/loader.conf" ]; then
warning "systemd-boot detected - you may need to update boot entries manually"
fi
}
# Prepare for safe reboot
prepare_reboot() {
log "Preparing for safe reboot..."
# Sync filesystem
log "Syncing filesystems..."
sync
# Remount root as read-only
log "Remounting root filesystem as read-only..."
mount / -o remount,ro 2>/dev/null || {
warning "Could not remount root as read-only"
}
success "System prepared for reboot"
echo
echo "=========================================="
echo "Migration completed successfully!"
echo "=========================================="
echo
echo "Next steps:"
echo "1. Exit the chroot environment"
echo "2. Reboot the system (cold reboot required)"
echo "3. The system should boot with OpenRC"
echo
echo "If you need to force a cold reboot, use:"
echo " echo s > /proc/sysrq-trigger"
echo " echo u > /proc/sysrq-trigger"
echo " echo b > /proc/sysrq-trigger"
echo
}
# Main execution
main() {
log "Starting Dinit to OpenRC migration check..."
# Pre-flight checks
check_chroot
# Check what init system we have and what to do
if check_init_system; then
log "Migration needed - proceeding with dinit to OpenRC migration"
# Create backup directory
mkdir -p /root/dinit-migration-backup
cd /root/dinit-migration-backup
# Execute migration steps
backup_services
download_openrc_packages
remove_dinit
install_openrc
configure_services
update_bootloader
prepare_reboot
success "Migration script completed successfully!"
else
log "Migration check completed"
exit 0
fi
}
# Run main function
main "$@"
The script follows this decision tree:
- Check chroot environment (safety)
- Detect init system state:
- Dinit present, OpenRC absent → Run migration
- OpenRC present, dinit absent → Check migration success
- Both present → Continue migration (cleanup partial state)
- Neither present → Error exit
- For migration success check:
- Count remaining dinit packages
- Verify OpenRC service configuration
- Test OpenRC command availability
- Report overall status
I hope someone else can benefit from this. I did, and I learned a lot!