Add minimal-linux-installer skill with proven installation patterns
This commit is contained in:
120
minimal-linux-installer/SKILL.md
Normal file
120
minimal-linux-installer/SKILL.md
Normal file
@@ -0,0 +1,120 @@
|
||||
---
|
||||
name: minimal-linux-installer
|
||||
description: Guide for creating robust, minimal Linux installers (Fedora-based) with systemd-boot, offline dnf support, and reliable user configuration. Use when building or debugging custom OS installers.
|
||||
---
|
||||
|
||||
# Minimal Linux Installer Guide
|
||||
|
||||
This skill provides proven patterns for building minimal, robust Linux installers, specifically targeting Fedora-based systems. It covers critical areas like bootloader configuration (systemd-boot), offline package management, and user account setup.
|
||||
|
||||
## Core Workflows
|
||||
|
||||
### 1. Partitioning & Mounting
|
||||
|
||||
**Guideline:** Always unmount partitions before modifying them. Mount pseudo-filesystems (including `efivarfs`) before chrooting.
|
||||
|
||||
```python
|
||||
# Unmount all partitions on target disk
|
||||
ensure_unmounted(target_disk)
|
||||
|
||||
# ... Partitioning logic (EFI @ 512MB+, Root) ...
|
||||
|
||||
# Mount pseudo-filesystems
|
||||
def mount_pseudo_fs(mount_root):
|
||||
mounts = ["dev", "proc", "sys"]
|
||||
for fs in mounts:
|
||||
run_command(["mount", "--bind", f"/{fs}", f"{mount_root}/{fs}"])
|
||||
|
||||
# Critical for UEFI variable updates
|
||||
if os.path.exists("/sys/firmware/efi/efivars"):
|
||||
run_command(["mount", "-t", "efivarfs", "efivarfs", f"{mount_root}/sys/firmware/efi/efivars"])
|
||||
```
|
||||
|
||||
### 2. Offline Package Installation (DNF)
|
||||
|
||||
**Guideline:** Prioritize local ISO repositories to allow offline installation. Fallback to network only if necessary.
|
||||
|
||||
```python
|
||||
# Search for ISO repo in common live media locations
|
||||
possible_repos = [
|
||||
"/run/install/repo",
|
||||
"/run/install/source",
|
||||
"/mnt/install/repo",
|
||||
"/run/initramfs/live",
|
||||
"/run/initramfs/isoscan"
|
||||
]
|
||||
# Also check /run/media/$USER/$LABEL
|
||||
|
||||
iso_repo = find_repo(possible_repos)
|
||||
|
||||
if iso_repo:
|
||||
# Strict offline mode
|
||||
dnf_args = [
|
||||
"--disablerepo=*",
|
||||
f"--repofrompath=local-iso,{iso_repo}",
|
||||
"--enablerepo=local-iso",
|
||||
"--cacheonly" # Critical for dnf5 to avoid metadata download
|
||||
]
|
||||
else:
|
||||
# Network fallback
|
||||
dnf_args = []
|
||||
|
||||
# Essential packages for a bootable minimal system
|
||||
packages = [
|
||||
"basesystem", "bash", "coreutils", "kernel", "systemd",
|
||||
"systemd-boot-unsigned", # Required for bootctl
|
||||
"dnf", "shadow-utils", "util-linux", # User mgmt & utils
|
||||
"efibootmgr", "passwd", "rootfiles", "vim-minimal"
|
||||
]
|
||||
```
|
||||
|
||||
### 3. Bootloader Configuration (systemd-boot)
|
||||
|
||||
**Guideline:** Use `bootctl` and `kernel-install` for a robust, standardized boot process. Set layout to `bls`.
|
||||
|
||||
```python
|
||||
# 1. Configure kernel layout
|
||||
with open(f"{mount_root}/etc/kernel/layout", "w") as f:
|
||||
f.write("bls\n")
|
||||
|
||||
# 2. Install bootloader
|
||||
# Remove --force if not supported by target version
|
||||
run_command(["chroot", mount_root, "bootctl", "install", "--path=/boot"])
|
||||
|
||||
# 3. Generate initramfs if missing
|
||||
if not os.path.exists(f"{mount_root}/boot/initramfs-{kver}.img"):
|
||||
run_command(["chroot", mount_root, "dracut", "--force", f"/boot/initramfs-{kver}.img", kver])
|
||||
|
||||
# 4. Add kernel entry
|
||||
# kernel-install add <kver> <image> <initrd>
|
||||
run_command(["chroot", mount_root, "kernel-install", "add", kver, kernel_image, initrd_path])
|
||||
```
|
||||
|
||||
### 4. Reliable User & Password Setup
|
||||
|
||||
**Guideline:** Avoid piping plaintext passwords to stdin of `chpasswd` inside chroot if possible. Pre-hash passwords on the host or use `usermod -p`.
|
||||
|
||||
```python
|
||||
# 1. Create User
|
||||
run_command(["chroot", mount_root, "useradd", "-m", "-G", "wheel", username])
|
||||
|
||||
# 2. Hash Password (Host-side)
|
||||
# openssl passwd -6 generates SHA512 hash
|
||||
hash = subprocess.check_output(["openssl", "passwd", "-6", password], text=True).strip()
|
||||
|
||||
# 3. Set Password (Directly modify shadow via usermod)
|
||||
run_command(["chroot", mount_root, "usermod", "-p", hash, username])
|
||||
run_command(["chroot", mount_root, "usermod", "-p", hash, "root"])
|
||||
|
||||
# 4. Ensure Sudo Access
|
||||
with open(f"{mount_root}/etc/sudoers.d/wheel", "w") as f:
|
||||
f.write("%wheel ALL=(ALL) ALL\n")
|
||||
```
|
||||
|
||||
### 5. Finalization
|
||||
|
||||
**Guideline:** Always `sync` to flush write buffers to physical media.
|
||||
|
||||
```python
|
||||
run_command(["sync"])
|
||||
```
|
||||
Reference in New Issue
Block a user