diff --git a/Dockerfile b/Dockerfile index d1e5e2b..2cc77c4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,35 +1,22 @@ -FROM --platform=linux/amd64 debian:trixie-slim AS builder +FROM --platform=$BUILDPLATFORM alpine AS builder -ARG VERSION_KVM_OPENCORE="v21" -ARG REPO_KVM_OPENCORE="https://github.com/thenickdude/KVM-Opencore" +ARG VERSION_OPENCORE="1.0.2" +ARG REPO_OPENCORE="https://github.com/acidanthera/OpenCorePkg" +ADD $REPO_OPENCORE/releases/download/$VERSION_OPENCORE/OpenCore-$VERSION_OPENCORE-RELEASE.zip /tmp/opencore.zip -ARG DEBCONF_NOWARNINGS="yes" -ARG DEBIAN_FRONTEND="noninteractive" -ARG DEBCONF_NONINTERACTIVE_SEEN="true" - -RUN set -eu && \ - apt-get update && \ - apt-get --no-install-recommends -y install \ - fdisk \ - mtools && \ - apt-get clean && \ - rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* - -COPY --chmod=755 ./src/build.sh /run -COPY --chmod=644 ./config.plist /run - -ADD $REPO_KVM_OPENCORE/releases/download/$VERSION_KVM_OPENCORE/OpenCore-$VERSION_KVM_OPENCORE.iso.gz /tmp/opencore.iso.gz - -RUN gzip -d /tmp/opencore.iso.gz && \ - run/build.sh /tmp/opencore.iso /run/config.plist && \ - rm -rf /tmp/* +RUN apk --update add unzip && \ + unzip /tmp/opencore.zip -d /tmp/oc && \ + cp /tmp/oc/Utilities/macserial/macserial.linux /macserial && \ + rm -rf /tmp/* /var/tmp/* /var/cache/apk/* FROM scratch AS runner -COPY --from=qemux/qemu-docker:6.07 / / +COPY --from=qemux/qemu-docker:6.08 / / ARG VERSION_ARG="0.0" +ARG VERSION_KVM_OPENCORE="v21" ARG VERSION_OSX_KVM="326053dd61f49375d5dfb28ee715d38b04b5cd8e" ARG REPO_OSX_KVM="https://raw.githubusercontent.com/kholia/OSX-KVM" +ARG REPO_KVM_OPENCORE="https://github.com/thenickdude/KVM-Opencore" ARG DEBCONF_NOWARNINGS="yes" ARG DEBIAN_FRONTEND="noninteractive" @@ -38,13 +25,17 @@ ARG DEBCONF_NONINTERACTIVE_SEEN="true" RUN set -eu && \ apt-get update && \ apt-get --no-install-recommends -y install \ + xxd \ + fdisk \ + mtools \ python3 && \ apt-get clean && \ echo "$VERSION_ARG" > /run/version && \ rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* COPY --chmod=755 ./src /run/ -COPY --chmod=644 --from=builder /images /images +COPY --chmod=644 ./config.plist / +COPY --chmod=755 --from=builder /macserial /usr/local/bin/ ADD --chmod=644 \ $REPO_OSX_KVM/$VERSION_OSX_KVM/OVMF_CODE.fd \ @@ -52,8 +43,10 @@ ADD --chmod=644 \ $REPO_OSX_KVM/$VERSION_OSX_KVM/OVMF_VARS-1024x768.fd \ $REPO_OSX_KVM/$VERSION_OSX_KVM/OVMF_VARS-1920x1080.fd /usr/share/OVMF/ -EXPOSE 8006 5900 +ADD $REPO_KVM_OPENCORE/releases/download/$VERSION_KVM_OPENCORE/OpenCore-$VERSION_KVM_OPENCORE.iso.gz /opencore.iso.gz + VOLUME /storage +EXPOSE 8006 5900 ENV VERSION="13" ENV RAM_SIZE="4G" diff --git a/readme.md b/readme.md index 7ee1874..259dc43 100644 --- a/readme.md +++ b/readme.md @@ -74,7 +74,7 @@ kubectl apply -f https://raw.githubusercontent.com/dockur/macos/refs/heads/maste - Choose `Disk Utility` and then select the largest `Apple Inc. VirtIO Block Media` disk. - - Click the `Erase` button to format the disk, and give it any recognizable name you like. + - Click the `Erase` button to format the disk to APFS, and give it any recognizable name you like. - Close the current window and proceed the installation by clicking `Reinstall macOS`. diff --git a/src/boot.sh b/src/boot.sh index 879253f..07955e4 100644 --- a/src/boot.sh +++ b/src/boot.sh @@ -2,34 +2,28 @@ set -Eeuo pipefail # Docker environment variables -: "${BOOT_MODE:="full"}" # Boot mode +: "${BOOT_MODE:="macos"}" # Boot mode BOOT_DESC="" BOOT_OPTS="" SECURE="off" OVMF="/usr/share/OVMF" -case "${BOOT_MODE,,}" in - "full" ) +case "${HEIGHT,,}" in + "1080" ) DEST="$PROCESS" - BOOT_DESC=" 1920x1080" ROM="OVMF_CODE.fd" VARS="OVMF_VARS-1920x1080.fd" ;; - "hd" ) + "768" ) DEST="${PROCESS}_hd" - BOOT_DESC=" 1024x768" ROM="OVMF_CODE.fd" VARS="OVMF_VARS-1024x768.fd" ;; - "default" ) - BOOT_DESC="" + *) ROM="OVMF_CODE.fd" VARS="OVMF_VARS.fd" - DEST="${PROCESS}_default" - ;; - *) - error "Unknown BOOT_MODE, value \"${BOOT_MODE}\" is not recognized!" && exit 33 + DEST="${PROCESS}_${HEIGHT}" ;; esac @@ -58,31 +52,104 @@ fi BOOT_OPTS+=" -drive if=pflash,format=raw,readonly=on,file=$DEST.rom" BOOT_OPTS+=" -drive if=pflash,format=raw,file=$DEST.vars" -# OpenCoreBoot -BOOT_DRIVE_ID="OpenCore" -BOOT_DRIVE="$STORAGE/boot.img" -BOOT_VERSION="$STORAGE/boot.version" -BOOT_FILE="/images/OpenCore.img.gz" -BOOT_SIZE=$(stat -c%s "$BOOT_FILE") - -CURRENT_SIZE="" -if [ -f "$BOOT_VERSION" ]; then - CURRENT_SIZE=$(<"$BOOT_VERSION") -fi +IMG="$STORAGE/boot.img" -if [ "$CURRENT_SIZE" != "$BOOT_SIZE" ]; then - rm -f "$BOOT_DRIVE" 2>/dev/null || true -fi +if [ ! -f "$IMG" ]; then + + FILE="OpenCore.img" + IMG="/tmp/$FILE" + rm -f "$IMG" -if [ ! -f "$BOOT_DRIVE" ] || [ ! -s "$BOOT_DRIVE" ]; then - msg="Extracting boot image" + # OpenCoreBoot + ISO="/opencore.iso" + OUT="/tmp/extract" + + rm -rf "$OUT" + mkdir -p "$OUT" + + msg="Building boot image" info "$msg..." && html "$msg..." - gzip -dkc "$BOOT_FILE" > "$BOOT_DRIVE" - echo "$BOOT_SIZE" > "$BOOT_VERSION" + + [ ! -f "$ISO" ] && gzip -dk "$ISO.gz" + + if [ ! -f "$ISO" ] || [ ! -s "$ISO" ]; then + error "Could not find image file \"$ISO\"." && exit 10 + fi + + START=$(sfdisk -l "$ISO" | grep -i -m 1 "EFI System" | awk '{print $2}') + mcopy -bspmQ -i "$ISO@@${START}S" ::EFI "$OUT" + + CFG="$OUT/EFI/OC/config.plist" + cp /config.plist "$CFG" + + ROM="${MAC//[^[:alnum:]]/}" + ROM="${ROM,,}" + BROM=$(echo "$ROM" | xxd -r -p | base64) + RESOLUTION="${WIDTH}x${HEIGHT}@32" + + sed -r -i -e 's|m7zhIYfl|'"${BROM}"'|g' "$CFG" + sed -r -i -e 's|iMacPro1,1|'"${MODEL}"'|g' "$CFG" + sed -r -i -e 's|C02TM2ZBHX87|'"${SN}"'|g' "$CFG" + sed -r -i -e 's|C02717306J9JG361M|'"${MLB}"'|g' "$CFG" + sed -r -i -e 's|1920x1080@32|'"${RESOLUTION}"'|g' "$CFG" + sed -r -i -e 's|007076A6-F2A2-4461-BBE5-BAD019F8025A|'"${UUID}"'|g' "$CFG" + + # Build image + + MB=256 + CLUSTER=4 + START=2048 + SECTOR=512 + FIRST_LBA=34 + + SIZE=$(( MB*1024*1024 )) + OFFSET=$(( START*SECTOR )) + TOTAL=$(( SIZE-(FIRST_LBA*SECTOR) )) + LAST_LBA=$(( TOTAL/SECTOR )) + COUNT=$(( LAST_LBA-(START-1) )) + + if ! truncate -s "$SIZE" "$IMG"; then + rm -f "$IMG" + error "Could not allocate space to create image $IMG ." && exit 11 + fi + + PART="/tmp/partition.fdisk" + + { echo "label: gpt" + echo "label-id: 1ACB1E00-3B8F-4B2A-86A4-D99ED21DCAEB" + echo "device: $FILE" + echo "unit: sectors" + echo "first-lba: $FIRST_LBA" + echo "last-lba: $LAST_LBA" + echo "sector-size: $SECTOR" + echo "" + echo "${FILE}1 : start=$START, size=$COUNT, type=C12A7328-F81F-11D2-BA4B-00A0C93EC93B, uuid=05157F6E-0AE8-4D1A-BEA5-AC172453D02C, name=\"primary\"" + + } > "$PART" + + sfdisk -q "$IMG" < "$PART" + echo "drive c: file=\"$IMG\" partition=0 offset=$OFFSET" > /etc/mtools.conf + + mformat -F -M "$SECTOR" -c "$CLUSTER" -T "$COUNT" -v "EFI" "C:" + mcopy -bspmQ "$OUT/EFI" "C:" + + rm -rf "$OUT" + + if [[ "$DEBUG" == [Yy1]* ]]; then + info "" + info "Model: $MODEL" + info "Rom: $ROM" + info "Serial: $SN" + info "Board: $MLB" + info "" + fi + fi +BOOT_DRIVE_ID="OpenCore" + DISK_OPTS+=" -device virtio-blk-pci,drive=${BOOT_DRIVE_ID},bus=pcie.0,addr=0x5,bootindex=$BOOT_INDEX" -DISK_OPTS+=" -drive file=$BOOT_DRIVE,id=$BOOT_DRIVE_ID,format=raw,cache=unsafe,readonly=on,if=none" +DISK_OPTS+=" -drive file=$IMG,id=$BOOT_DRIVE_ID,format=raw,cache=unsafe,readonly=on,if=none" CPU_VENDOR=$(lscpu | awk '/Vendor ID/{print $3}') DEFAULT_FLAGS="vendor=GenuineIntel,vmware-cpuid-freq=on,-pdpe1gb" diff --git a/src/build.sh b/src/build.sh deleted file mode 100644 index e68f1a7..0000000 --- a/src/build.sh +++ /dev/null @@ -1,77 +0,0 @@ -#!/usr/bin/env bash -set -Eeuo pipefail - -DST="/images" -OUT="/tmp/extract" - -rm -rf "$OUT" -rm -rf "$DST" - -mkdir -p "$OUT" -mkdir -p "$DST" - -echo "Extracting template image..." - -if [ ! -f "$1" ] || [ ! -s "$1" ]; then - echo "Could not find image file \"$1\"." && exit 10 -fi - -START=$(sfdisk -l "$1" | grep -i -m 1 "EFI System" | awk '{print $2}') -mcopy -bspmQ -i "$1@@${START}S" ::EFI "$OUT" - -echo "Building OpenCore image..." - -cp "$2" "$OUT/EFI/OC/" - -MB=256 -CLUSTER=4 -START=2048 -SECTOR=512 -FIRST_LBA=34 - -SIZE=$(( MB*1024*1024 )) -OFFSET=$(( START*SECTOR )) -TOTAL=$(( SIZE-(FIRST_LBA*SECTOR) )) -LAST_LBA=$(( TOTAL/SECTOR )) -COUNT=$(( LAST_LBA-(START-1) )) - -FILE="OpenCore.img" -IMG="/tmp/$FILE" -rm -f "$IMG" - -if ! truncate -s "$SIZE" "$IMG"; then - rm -f "$IMG" - echo "Could not allocate file $IMG for the OpenCore image." && exit 11 -fi - -PART="/tmp/partition.fdisk" - -{ echo "label: gpt" - echo "label-id: 1ACB1E00-3B8F-4B2A-86A4-D99ED21DCAEB" - echo "device: $FILE" - echo "unit: sectors" - echo "first-lba: $FIRST_LBA" - echo "last-lba: $LAST_LBA" - echo "sector-size: $SECTOR" - echo "" - echo "${FILE}1 : start=$START, size=$COUNT, type=C12A7328-F81F-11D2-BA4B-00A0C93EC93B, uuid=05157F6E-0AE8-4D1A-BEA5-AC172453D02C, name=\"primary\"" - -} > "$PART" - -sfdisk -q "$IMG" < "$PART" - -echo "drive c: file=\"$IMG\" partition=0 offset=$OFFSET" > /etc/mtools.conf - -mformat -F -M "$SECTOR" -c "$CLUSTER" -T "$COUNT" -v "EFI" "C:" - -echo "Copying files to image..." - -mcopy -bspmQ "$OUT/EFI" "C:" -rm -rf "$OUT" - -echo "Compressing image..." - -gzip -c "$IMG" > "$DST/$FILE.gz" -rm -f "$IMG" - -echo "Finished succesfully!" diff --git a/src/install.sh b/src/install.sh index 3322c21..7d2eed5 100644 --- a/src/install.sh +++ b/src/install.sh @@ -3,12 +3,14 @@ set -Eeuo pipefail # Docker environment variables -: "${SN:=""}" -: "${MLB:=""}" -: "${MAC:=""}" -: "${UUID:=""}" -: "${MODEL:="iMacPro1,1"}" -: "${VERSION:="13"}" # OSX Version +: "${SN:=""}" # Device serial +: "${MLB:=""}" # Board serial +: "${MAC:=""}" # MAC address +: "${UUID:=""}" # Unique ID +: "${WIDTH:="1920"}" # Horizontal +: "${HEIGHT:="1080"}" # Vertical +: "${VERSION:="13"}" # OSX Version +: "${MODEL:="iMacPro1,1"}" # Device model TMP="$STORAGE/tmp" BASE_IMG_ID="InstallMedia" @@ -76,8 +78,9 @@ generateID() { [ -s "$file" ] && UUID=$(<"$file") [ -n "$UUID" ] && return 0 - UUID=$(cat /proc/sys/kernel/random/uuid) - echo "${UUID^^}" > "$file" + UUID=$(cat /proc/sys/kernel/random/uuid 2> /dev/null || uuidgen --random) + UUID="${UUID^^}" + echo "$UUID" > "$file" return 0 } @@ -92,7 +95,35 @@ generateAddress() { # Generate Apple MAC address based on Docker container ID in hostname MAC=$(echo "$HOST" | md5sum | sed 's/^\(..\)\(..\)\(..\)\(..\)\(..\).*$/00:16:cb:\3:\4:\5/') - echo "${MAC^^}" > "$file" + MAC="${MAC^^}" + echo "$MAC" > "$file" + + return 0 +} + +generateSerial() { + + local file="$STORAGE/$PROCESS.sn" + local file2="$STORAGE/$PROCESS.mlb" + + [ -n "$SN" ] && [ -n "$MLB" ] && return 0 + [ -s "$file" ] && SN=$(<"$file") + [ -s "$file2" ] && MLB=$(<"$file2") + [ -n "$SN" ] && [ -n "$MLB" ] && return 0 + + # Generate unique serial numbers for machine + SN=$(/usr/local/bin/macserial --num 1 --model "${MODEL}" 2>/dev/null) + + SN="${SN##*$'\n'}" + [[ "$SN" != *" | "* ]] && error "$SN" && return 1 + + MLB=${SN#*|} + MLB="${MLB#"${MLB%%[![:space:]]*}"}" + SN="${SN%%|*}" + SN="${SN%"${SN##*[![:space:]]}"}" + + echo "$SN" > "$file" + echo "$MLB" > "$file2" return 0 } @@ -121,8 +152,12 @@ if ! generateID; then error "Failed to generate UUID!" && exit 35 fi +if ! generateSerial; then + error "Failed to generate serialnumber!" && exit 36 +fi + if ! generateAddress; then - error "Failed to generate MAC address!" && exit 36 + error "Failed to generate MAC address!" && exit 37 fi DISK_OPTS="-device virtio-blk-pci,drive=${BASE_IMG_ID},bus=pcie.0,addr=0x6"