mirror of
https://github.com/bin456789/reinstall.git
synced 2026-02-21 10:27:50 +08:00
Update reinstall-freebsd-linux.sh
This commit is contained in:
parent
b4727edb4c
commit
b0ce72719d
@ -1 +1,655 @@
|
||||
#!/usr/bin/env bash
|
||||
# reinstall-freebsd-linux.sh
|
||||
# Reinstall system on Linux / FreeBSD using DD + cloud-init (NoCloud) with:
|
||||
# - freebsd
|
||||
# - rocky
|
||||
# - almalinux
|
||||
# - fedora
|
||||
# - redhat
|
||||
#
|
||||
# All target systems use cloud-init to inject:
|
||||
# - root password (--password)
|
||||
# - SSH public key(s) (--ssh-key, multiple)
|
||||
# - SSH port (--ssh-port)
|
||||
# - optional FRPC config (--frpc-toml) stored as EFI:/nocloud/frpc.toml
|
||||
#
|
||||
# Requirements:
|
||||
# - Run with bash: bash reinstall-freebsd-linux.sh ...
|
||||
# - Needs dd, xz, qemu-img, mount, and curl or wget or fetch
|
||||
|
||||
set -eE
|
||||
|
||||
SCRIPT_NAME="${0##*/}"
|
||||
|
||||
error() {
|
||||
echo "ERROR: $*" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
warn() {
|
||||
echo "WARN: $*" >&2
|
||||
}
|
||||
|
||||
info() {
|
||||
echo "==> $*"
|
||||
}
|
||||
|
||||
usage() {
|
||||
cat <<EOF
|
||||
Usage:
|
||||
$SCRIPT_NAME freebsd 14 --disk /dev/sdX [options...]
|
||||
$SCRIPT_NAME rocky 10 --disk /dev/sdX [options...]
|
||||
$SCRIPT_NAME almalinux 10 --disk /dev/sdX [options...]
|
||||
$SCRIPT_NAME fedora 43 --disk /dev/sdX [options...]
|
||||
$SCRIPT_NAME redhat --disk /dev/sdX --img URL [options...]
|
||||
|
||||
Options:
|
||||
--disk DISK Target disk, e.g. /dev/sda, /dev/vda, /dev/nvme0n1, /dev/ada0
|
||||
If you omit /dev/, the script will automatically prefix /dev/.
|
||||
|
||||
--img URL Override default image URL (redhat requires this).
|
||||
Supports http:// and https://
|
||||
|
||||
--password PASSWORD Set root password. When using --ssh-key only, password can be empty
|
||||
(SSH key login only).
|
||||
|
||||
--ssh-key KEY Set SSH public key, can be specified multiple times. Supported forms:
|
||||
--ssh-key "ssh-rsa AAAA... comment"
|
||||
--ssh-key "ssh-ed25519 AAAA... comment"
|
||||
--ssh-key "ecdsa-sha2-nistp256/384/521 AAAA... comment"
|
||||
--ssh-key http://path/to/public_key
|
||||
--ssh-key https://path/to/public_key
|
||||
--ssh-key github:your_username
|
||||
--ssh-key gitlab:your_username
|
||||
--ssh-key /path/to/public_key
|
||||
--ssh-key C:\\path\\to\\public_key (not supported directly, copy to local file first)
|
||||
|
||||
--ssh-port PORT Change SSH port in the new system. cloud-init will try to modify
|
||||
sshd_config and restart sshd.
|
||||
|
||||
--web-port PORT Reserved for web log port. This script only writes it into cloud-init,
|
||||
you can consume it later from within the system.
|
||||
|
||||
--frpc-toml PATH/URL Add FRPC configuration for tunneling:
|
||||
- Local path: copy to EFI:/nocloud/frpc.toml
|
||||
- HTTP(S): download to EFI:/nocloud/frpc.toml
|
||||
cloud-init will add a runcmd section that tries to copy this to /etc/frp
|
||||
and start frpc if available.
|
||||
|
||||
--hold 1 Only validate and print planned actions, do not download or write disk.
|
||||
Useful for connectivity/parameter checks.
|
||||
--hold 2 Perform dd + NoCloud injection but do NOT reboot. Useful to inspect or
|
||||
chroot into the new system before first boot.
|
||||
|
||||
Examples:
|
||||
bash $SCRIPT_NAME freebsd 14 --disk /dev/sda --ssh-key "ssh-ed25519 AAAA... comment"
|
||||
bash $SCRIPT_NAME rocky 10 --disk /dev/sda --ssh-key github:your_name
|
||||
bash $SCRIPT_NAME almalinux 10 --disk /dev/sda --password "P@ssw0rd"
|
||||
bash $SCRIPT_NAME fedora 43 --disk /dev/vda --ssh-key https://example.com/id_ed25519.pub
|
||||
bash $SCRIPT_NAME redhat --img "https://access.cdn.redhat.com/...qcow2?...auth..." --disk /dev/sda --ssh-key "ssh-ed25519 AAAA... comment"
|
||||
|
||||
Notes:
|
||||
* This script will dd an entire disk. Make sure --disk is correct!
|
||||
* All target systems use cloud-init NoCloud to inject root password, SSH keys, etc.
|
||||
EOF
|
||||
exit 1
|
||||
}
|
||||
|
||||
to_lower() {
|
||||
tr 'A-Z' 'a-z'
|
||||
}
|
||||
|
||||
is_port_valid() {
|
||||
[[ "$1" =~ ^[0-9]+$ ]] && [ "$1" -ge 1 ] && [ "$1" -le 65535 ]
|
||||
}
|
||||
|
||||
http_download() {
|
||||
local url="$1" dst="$2"
|
||||
if command -v curl >/dev/null 2>&1; then
|
||||
curl -L --fail -o "$dst" "$url"
|
||||
elif command -v wget >/dev/null 2>&1; then
|
||||
wget -O "$dst" "$url"
|
||||
elif command -v fetch >/dev/null 2>&1; then
|
||||
fetch -o "$dst" "$url"
|
||||
else
|
||||
error "No curl/wget/fetch found, cannot download: $url"
|
||||
fi
|
||||
}
|
||||
|
||||
detect_os_arch() {
|
||||
OS=$(uname -s)
|
||||
ARCH=$(uname -m)
|
||||
|
||||
case "$OS" in
|
||||
Linux|FreeBSD) ;;
|
||||
*) error "Unsupported OS: $OS (only Linux and FreeBSD are supported)" ;;
|
||||
esac
|
||||
|
||||
case "$ARCH" in
|
||||
x86_64|amd64) MACHINE_ARCH="x86_64" ;;
|
||||
aarch64|arm64) MACHINE_ARCH="aarch64" ;;
|
||||
*)
|
||||
warn "Unknown arch: $ARCH, image URL selection may fail"
|
||||
MACHINE_ARCH="$ARCH"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Parse ssh-key: supports inline / URL / github / gitlab / file
|
||||
parse_ssh_key() {
|
||||
local val="$1"
|
||||
local val_lower key_url tmpfile ssh_key
|
||||
|
||||
ssh_key_error_and_exit() {
|
||||
error "$1
|
||||
Available options:
|
||||
--ssh-key \"ssh-rsa ...\"
|
||||
--ssh-key \"ssh-ed25519 ...\"
|
||||
--ssh-key \"ecdsa-sha2-nistp256/384/521 ...\"
|
||||
--ssh-key github:your_username
|
||||
--ssh-key gitlab:your_username
|
||||
--ssh-key http://path/to/public_key
|
||||
--ssh-key https://path/to/public_key
|
||||
--ssh-key /path/to/public_key
|
||||
--ssh-key C:\\path\\to\\public_key (not supported directly, copy to a local path first)"
|
||||
}
|
||||
|
||||
is_valid_ssh_key() {
|
||||
grep -qE '^(ecdsa-sha2-nistp(256|384|521)|ssh-(ed25519|rsa)) ' <<<"$1"
|
||||
}
|
||||
|
||||
val_lower=$(to_lower <<<"$val")
|
||||
|
||||
case "$val_lower" in
|
||||
github:*|gitlab:*|http://*|https://*)
|
||||
if [[ "$val_lower" == http* ]]; then
|
||||
key_url="$val"
|
||||
else
|
||||
IFS=: read -r site user <<<"$val"
|
||||
[ -n "$user" ] || ssh_key_error_and_exit "Need a username for $site"
|
||||
key_url="https://$site.com/$user.keys"
|
||||
fi
|
||||
info "Downloading SSH key from: $key_url"
|
||||
tmpfile=$(mktemp /tmp/reinstall-sshkey.XXXXXX)
|
||||
if ! http_download "$key_url" "$tmpfile"; then
|
||||
rm -f "$tmpfile"
|
||||
ssh_key_error_and_exit "Failed to download SSH key from $key_url"
|
||||
fi
|
||||
ssh_key=$(grep -m1 -E '^(ecdsa-sha2-nistp(256|384|521)|ssh-(ed25519|rsa)) ' "$tmpfile" || true)
|
||||
rm -f "$tmpfile"
|
||||
[ -n "$ssh_key" ] || ssh_key_error_and_exit "No valid SSH key found in $key_url"
|
||||
;;
|
||||
*)
|
||||
# Reject Windows-style paths explicitly
|
||||
if [[ "$val" =~ ^[A-Za-z]:\\ ]]; then
|
||||
ssh_key_error_and_exit "Windows path is not supported, please copy the key file to local filesystem and use /path/to/public_key"
|
||||
fi
|
||||
# Inline key or local file
|
||||
if is_valid_ssh_key "$val"; then
|
||||
ssh_key="$val"
|
||||
else
|
||||
if [ ! -f "$val" ]; then
|
||||
ssh_key_error_and_exit "SSH key/file/url \"$val\" is invalid (file not found)"
|
||||
fi
|
||||
ssh_key=$(grep -m1 -E '^(ecdsa-sha2-nistp(256|384|521)|ssh-(ed25519|rsa)) ' "$val" || true)
|
||||
[ -n "$ssh_key" ] || ssh_key_error_and_exit "No valid SSH key found in file: $val"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
echo "$ssh_key"
|
||||
}
|
||||
|
||||
# Choose default image URL based on target OS, version, and host arch
|
||||
get_default_image_url() {
|
||||
local os="$1" ver="$2"
|
||||
|
||||
case "$os" in
|
||||
freebsd)
|
||||
case "$ver" in
|
||||
14|14.*)
|
||||
case "$MACHINE_ARCH" in
|
||||
x86_64)
|
||||
echo "https://download.freebsd.org/releases/VM-IMAGES/14.3-RELEASE/amd64/Latest/FreeBSD-14.3-RELEASE-amd64-BASIC-CLOUDINIT-ufs.qcow2.xz"
|
||||
;;
|
||||
aarch64)
|
||||
echo "https://download.freebsd.org/releases/VM-IMAGES/14.3-RELEASE/aarch64/Latest/FreeBSD-14.3-RELEASE-arm64-aarch64-BASIC-CLOUDINIT-ufs.qcow2.xz"
|
||||
;;
|
||||
*)
|
||||
error "Current arch $MACHINE_ARCH is not supported for automatic FreeBSD image selection, please specify --img manually"
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
*)
|
||||
error "Unsupported FreeBSD version: $ver (only 14.x is baked in; use --img for others)"
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
rocky)
|
||||
case "$ver" in
|
||||
10)
|
||||
case "$MACHINE_ARCH" in
|
||||
x86_64)
|
||||
echo "https://download.rockylinux.org/pub/rocky/10/images/x86_64/Rocky-10-EC2-LVM.latest.x86_64.qcow2"
|
||||
;;
|
||||
*)
|
||||
error "Rocky 10 default image is only provided for x86_64; use --img for other arches"
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
*)
|
||||
error "Unsupported Rocky version: $ver (future: add rocky 9, etc.)"
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
almalinux)
|
||||
case "$ver" in
|
||||
10)
|
||||
case "$MACHINE_ARCH" in
|
||||
x86_64)
|
||||
echo "https://repo.almalinux.org/almalinux/10/cloud/x86_64/images/AlmaLinux-10-GenericCloud-latest.x86_64.qcow2"
|
||||
;;
|
||||
aarch64)
|
||||
echo "https://repo.almalinux.org/almalinux/10/cloud/aarch64/images/AlmaLinux-10-GenericCloud-latest.aarch64.qcow2"
|
||||
;;
|
||||
*)
|
||||
error "Current arch $MACHINE_ARCH is not supported for automatic AlmaLinux image selection, please specify --img manually"
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
*)
|
||||
error "Unsupported AlmaLinux version: $ver"
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
fedora)
|
||||
case "$ver" in
|
||||
43)
|
||||
case "$MACHINE_ARCH" in
|
||||
x86_64)
|
||||
echo "https://download.fedoraproject.org/pub/fedora/linux/releases/43/Cloud/x86_64/images/Fedora-Cloud-Base-Generic-43-1.6.x86_64.qcow2"
|
||||
;;
|
||||
aarch64)
|
||||
echo "https://download.fedoraproject.org/pub/fedora/linux/releases/43/Cloud/aarch64/images/Fedora-Cloud-Base-Generic-43-1.6.aarch64.qcow2"
|
||||
;;
|
||||
*)
|
||||
error "Current arch $MACHINE_ARCH is not supported for automatic Fedora image selection, please specify --img manually"
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
*)
|
||||
error "Unsupported Fedora version: $ver"
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
redhat)
|
||||
# Red Hat image must be supplied by user via --img
|
||||
echo ""
|
||||
;;
|
||||
*)
|
||||
error "Unknown target OS: $os"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
find_efi_partition() {
|
||||
# Guess EFI partition name from disk path (p1 vs 1)
|
||||
local disk="$1" part
|
||||
case "$disk" in
|
||||
*/nvme*|*/*nvd*)
|
||||
part="${disk}p1"
|
||||
;;
|
||||
*)
|
||||
# /dev/sda /dev/vda /dev/ada0 etc.
|
||||
if [[ "$(uname -s)" == "FreeBSD" ]]; then
|
||||
part="${disk}p1"
|
||||
else
|
||||
part="${disk}1"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
echo "$part"
|
||||
}
|
||||
|
||||
write_nocloud_seed() {
|
||||
local os="$1" meta_path="$2" user_path="$3"
|
||||
|
||||
mkdir -p "$(dirname "$meta_path")"
|
||||
|
||||
# meta-data
|
||||
cat >"$meta_path" <<EOF
|
||||
instance-id: iid-$(date +%s)
|
||||
local-hostname: $os
|
||||
EOF
|
||||
|
||||
# user-data (cloud-config)
|
||||
{
|
||||
echo "#cloud-config"
|
||||
|
||||
if [ -n "$PASSWORD" ]; then
|
||||
cat <<EOF
|
||||
ssh_pwauth: true
|
||||
disable_root: false
|
||||
chpasswd:
|
||||
list: |
|
||||
root:${PASSWORD}
|
||||
expire: false
|
||||
EOF
|
||||
fi
|
||||
|
||||
if [ -n "$SSH_KEYS_ALL" ]; then
|
||||
echo "ssh_authorized_keys:"
|
||||
while IFS= read -r line; do
|
||||
[ -n "$line" ] || continue
|
||||
printf ' - %s\n' "$line"
|
||||
done <<<"$SSH_KEYS_ALL"
|
||||
fi
|
||||
|
||||
# Example of writing web-port to a file for later use
|
||||
if [ -n "$WEB_PORT" ]; then
|
||||
cat <<EOF
|
||||
|
||||
write_files:
|
||||
- path: /etc/reinstall-web-port
|
||||
permissions: '0644'
|
||||
owner: root:root
|
||||
content: |
|
||||
$WEB_PORT
|
||||
EOF
|
||||
fi
|
||||
|
||||
# runcmd: change SSH port + optional FRPC
|
||||
if [ -n "$SSH_PORT" ] || [ -n "$FRPC_PRESENT" ]; then
|
||||
echo
|
||||
echo "runcmd:"
|
||||
fi
|
||||
|
||||
if [ -n "$SSH_PORT" ]; then
|
||||
cat <<EOF
|
||||
- |
|
||||
# Try to change SSH port on Linux / FreeBSD
|
||||
if [ -f /etc/ssh/sshd_config ]; then
|
||||
sed -i 's/^#Port .*/Port ${SSH_PORT}/' /etc/ssh/sshd_config 2>/dev/null || \
|
||||
sed -i 's/^Port .*/Port ${SSH_PORT}/' /etc/ssh/sshd_config 2>/dev/null || \
|
||||
sed -i '' 's/^#Port .*/Port ${SSH_PORT}/' /etc/ssh/sshd_config 2>/dev/null || \
|
||||
sed -i '' 's/^Port .*/Port ${SSH_PORT}/' /etc/ssh/sshd_config 2>/dev/null || true
|
||||
fi
|
||||
service sshd restart 2>/dev/null || systemctl restart sshd 2>/dev/null || true
|
||||
EOF
|
||||
fi
|
||||
|
||||
if [ -n "$FRPC_PRESENT" ]; then
|
||||
cat <<'EOF'
|
||||
- |
|
||||
# If EFI nocloud contains frpc.toml, copy to /etc/frp and try to start frpc
|
||||
if [ -f /boot/efi/nocloud/frpc.toml ]; then
|
||||
mkdir -p /etc/frp
|
||||
cp /boot/efi/nocloud/frpc.toml /etc/frp/frpc.toml
|
||||
(frpc -c /etc/frp/frpc.toml || /usr/local/bin/frpc -c /etc/frp/frpc.toml || true) &
|
||||
fi
|
||||
EOF
|
||||
fi
|
||||
} >"$user_path"
|
||||
}
|
||||
|
||||
# ----------------- main -----------------
|
||||
|
||||
[ $# -lt 1 ] && usage
|
||||
|
||||
TARGET_OS=$(echo "$1" | to_lower)
|
||||
shift || true
|
||||
|
||||
TARGET_VER=""
|
||||
IMG_URL=""
|
||||
DISK=""
|
||||
PASSWORD=""
|
||||
SSH_KEYS_ALL=""
|
||||
SSH_PORT=""
|
||||
WEB_PORT=""
|
||||
FRPC_TOML=""
|
||||
FRPC_PRESENT=""
|
||||
HOLD="0"
|
||||
|
||||
# If the next positional arg is numeric, treat it as version for specific OSes.
|
||||
if [ $# -gt 0 ] && [[ "$1" =~ ^[0-9]+$ ]]; then
|
||||
case "$TARGET_OS" in
|
||||
freebsd|rocky|almalinux|fedora)
|
||||
TARGET_VER="$1"
|
||||
shift
|
||||
;;
|
||||
redhat)
|
||||
error "Do not specify a version for redhat. Use: $SCRIPT_NAME redhat --img URL --disk /dev/XXX ..."
|
||||
;;
|
||||
*)
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
-h|--help)
|
||||
usage
|
||||
;;
|
||||
--disk)
|
||||
shift
|
||||
[ -n "$1" ] || error "Need value for --disk"
|
||||
DISK="$1"
|
||||
;;
|
||||
--disk=*)
|
||||
DISK="${1#*=}"
|
||||
;;
|
||||
--img)
|
||||
shift
|
||||
[ -n "$1" ] || error "Need value for --img"
|
||||
IMG_URL="$1"
|
||||
;;
|
||||
--img=*)
|
||||
IMG_URL="${1#*=}"
|
||||
;;
|
||||
--password|--passwd)
|
||||
shift
|
||||
[ -n "$1" ] || error "Need value for --password"
|
||||
PASSWORD="$1"
|
||||
;;
|
||||
--ssh-key|--public-key)
|
||||
shift
|
||||
[ -n "$1" ] || error "Need value for --ssh-key"
|
||||
key_line=$(parse_ssh_key "$1")
|
||||
if [ -n "$SSH_KEYS_ALL" ]; then
|
||||
SSH_KEYS_ALL+=$'\n'
|
||||
fi
|
||||
SSH_KEYS_ALL+="$key_line"
|
||||
;;
|
||||
--ssh-port)
|
||||
shift
|
||||
[ -n "$1" ] || error "Need value for --ssh-port"
|
||||
is_port_valid "$1" || error "Invalid --ssh-port: $1"
|
||||
SSH_PORT="$1"
|
||||
;;
|
||||
--web-port)
|
||||
shift
|
||||
[ -n "$1" ] || error "Need value for --web-port"
|
||||
is_port_valid "$1" || error "Invalid --web-port: $1"
|
||||
WEB_PORT="$1"
|
||||
;;
|
||||
--frpc-toml)
|
||||
shift
|
||||
[ -n "$1" ] || error "Need value for --frpc-toml"
|
||||
FRPC_TOML="$1"
|
||||
;;
|
||||
--hold)
|
||||
shift
|
||||
[ -n "$1" ] || error "Need value for --hold"
|
||||
[[ "$1" == "1" || "$1" == "2" ]] || error "Invalid --hold: $1 (must be 1 or 2)"
|
||||
HOLD="$1"
|
||||
;;
|
||||
*)
|
||||
error "Unknown argument: $1"
|
||||
;;
|
||||
esac
|
||||
shift || true
|
||||
done
|
||||
|
||||
[ -n "$DISK" ] || error "You must specify --disk, e.g. --disk /dev/sda or --disk /dev/ada0"
|
||||
|
||||
# Normalize disk path
|
||||
if [[ "$DISK" != /dev/* ]]; then
|
||||
DISK="/dev/$DISK"
|
||||
fi
|
||||
|
||||
if [ ! -b "$DISK" ] && [ ! -c "$DISK" ]; then
|
||||
error "Target disk $DISK does not exist or is not a block/char device"
|
||||
fi
|
||||
|
||||
detect_os_arch
|
||||
|
||||
# Default versions
|
||||
if [ -z "$TARGET_VER" ]; then
|
||||
case "$TARGET_OS" in
|
||||
freebsd) TARGET_VER="14" ;;
|
||||
rocky) TARGET_VER="10" ;;
|
||||
almalinux) TARGET_VER="10" ;;
|
||||
fedora) TARGET_VER="43" ;;
|
||||
redhat) TARGET_VER="" ;; # user must provide image
|
||||
*) ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Get default image URL (redhat requires user-supplied --img)
|
||||
if [ -z "$IMG_URL" ]; then
|
||||
IMG_URL=$(get_default_image_url "$TARGET_OS" "$TARGET_VER")
|
||||
if [ -z "$IMG_URL" ] && [ "$TARGET_OS" = "redhat" ]; then
|
||||
error "For redhat you must specify image URL with --img"
|
||||
fi
|
||||
fi
|
||||
|
||||
info "Host: OS=$OS ARCH=$ARCH ($MACHINE_ARCH)"
|
||||
info "Target: $TARGET_OS ${TARGET_VER:-"(no version)"}"
|
||||
info "Disk: $DISK"
|
||||
info "Image URL: $IMG_URL"
|
||||
|
||||
if [ "$HOLD" = "1" ]; then
|
||||
info "--hold 1 is set: only parameter check and summary, no download or disk write."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
TMPDIR=$(mktemp -d /tmp/reinstall-cloudinit.XXXXXX)
|
||||
trap 'rm -rf "$TMPDIR"' EXIT
|
||||
|
||||
IMG_QCOW="$TMPDIR/image.qcow2"
|
||||
IMG_RAW="$TMPDIR/image.raw"
|
||||
|
||||
# Download image
|
||||
info "Downloading image..."
|
||||
http_download "$IMG_URL" "$IMG_QCOW"
|
||||
|
||||
# Check if it's xz compressed
|
||||
if file "$IMG_QCOW" | grep -qi 'xz compressed'; then
|
||||
info "Detected xz compressed image, decompressing..."
|
||||
if ! command -v xz >/dev/null 2>&1; then
|
||||
error "xz not found, please install xz-utils / xz"
|
||||
fi
|
||||
mv "$IMG_QCOW" "$IMG_QCOW.xz"
|
||||
xz -dc "$IMG_QCOW.xz" >"$IMG_QCOW"
|
||||
fi
|
||||
|
||||
# Convert to raw using qemu-img
|
||||
info "Converting qcow2 to raw with qemu-img..."
|
||||
if ! command -v qemu-img >/dev/null 2>&1; then
|
||||
error "qemu-img not found; install qemu-img (Linux) or qemu-tools (FreeBSD) first"
|
||||
fi
|
||||
|
||||
qemu-img convert -O raw "$IMG_QCOW" "$IMG_RAW"
|
||||
|
||||
# Final confirmation
|
||||
echo
|
||||
echo "WARNING: dd will be run on $DISK. ALL DATA ON THIS DISK WILL BE LOST!"
|
||||
read -r -p "Type 'yes' to continue: " ans
|
||||
if [ "$ans" != "yes" ]; then
|
||||
error "Operation cancelled by user."
|
||||
fi
|
||||
|
||||
# dd to disk
|
||||
info "Writing image to disk with dd, this may take a while..."
|
||||
dd if="$IMG_RAW" of="$DISK" bs=4M conv=fsync status=progress
|
||||
sync
|
||||
info "dd finished."
|
||||
|
||||
# Try to refresh partition table (best-effort)
|
||||
if command -v partprobe >/dev/null 2>&1; then
|
||||
partprobe "$DISK" || true
|
||||
elif command -v blockdev >/dev/null 2>&1; then
|
||||
blockdev --rereadpt "$DISK" || true
|
||||
fi
|
||||
|
||||
sleep 2
|
||||
|
||||
# Find and mount EFI partition
|
||||
EFI_PART=$(find_efi_partition "$DISK")
|
||||
info "Trying EFI partition: $EFI_PART"
|
||||
|
||||
MNT_EFI="$TMPDIR/efi"
|
||||
mkdir -p "$MNT_EFI"
|
||||
|
||||
if [[ "$OS" == "FreeBSD" ]]; then
|
||||
if ! mount -t msdosfs "$EFI_PART" "$MNT_EFI" 2>/dev/null; then
|
||||
warn "Failed to mount EFI partition $EFI_PART, skipping cloud-init NoCloud injection."
|
||||
EFI_PART=""
|
||||
fi
|
||||
else
|
||||
if ! mount "$EFI_PART" "$MNT_EFI" 2>/dev/null; then
|
||||
# Some systems require explicit vfat
|
||||
if ! mount -t vfat "$EFI_PART" "$MNT_EFI" 2>/dev/null && ! mount -t msdos "$EFI_PART" "$MNT_EFI" 2>/dev/null; then
|
||||
warn "Failed to mount EFI partition $EFI_PART, skipping cloud-init NoCloud injection."
|
||||
EFI_PART=""
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -n "$EFI_PART" ]; then
|
||||
NOCLOUD_DIR="$MNT_EFI/nocloud"
|
||||
mkdir -p "$NOCLOUD_DIR"
|
||||
|
||||
# Handle FRPC config if present
|
||||
if [ -n "$FRPC_TOML" ]; then
|
||||
FRPC_PRESENT=1
|
||||
if [[ "$FRPC_TOML" =~ ^https?:// ]]; then
|
||||
info "Downloading FRPC config: $FRPC_TOML"
|
||||
if ! http_download "$FRPC_TOML" "$NOCLOUD_DIR/frpc.toml"; then
|
||||
warn "Failed to download FRPC config, ignoring"
|
||||
FRPC_PRESENT=""
|
||||
fi
|
||||
elif [ -f "$FRPC_TOML" ]; then
|
||||
info "Copying FRPC config from: $FRPC_TOML"
|
||||
cp "$FRPC_TOML" "$NOCLOUD_DIR/frpc.toml"
|
||||
else
|
||||
warn "Invalid FRPC config path: $FRPC_TOML, ignoring"
|
||||
FRPC_PRESENT=""
|
||||
fi
|
||||
fi
|
||||
|
||||
info "Writing NoCloud seed to EFI:/nocloud/ ..."
|
||||
write_nocloud_seed "$TARGET_OS" "$NOCLOUD_DIR/meta-data" "$NOCLOUD_DIR/user-data"
|
||||
|
||||
sync
|
||||
umount "$MNT_EFI" || true
|
||||
else
|
||||
warn "EFI could not be mounted; target system can still boot, but cloud-init configuration may not be applied."
|
||||
fi
|
||||
|
||||
info "Image write and cloud-init NoCloud injection completed."
|
||||
|
||||
if [ "$HOLD" = "2" ]; then
|
||||
info "--hold 2 is set: will NOT reboot automatically. You can inspect or chroot into the new system manually."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "You can now reboot into the new system, for example:"
|
||||
if [ "$OS" = "FreeBSD" ]; then
|
||||
echo " shutdown -r now"
|
||||
else
|
||||
echo " reboot"
|
||||
fi
|
||||
|
||||
exit 0
|
||||
|
||||
Loading…
Reference in New Issue
Block a user