mirror of
https://github.com/AuxXxilium/arc.git
synced 2026-09-03 06:36:32 +08:00
thttpd does not remove its pidfile when it dies, so a crash left the file behind pointing at a dead pid. The boot guard only tested that the file existed, concluded the server was up and skipped the restart, so nothing was listening while the loader carried on and reported an ip. That is the connection refused on a running system. Test the pid with kill -0 instead and clear the file before restarting. The shipped init script had no monitor loop to catch this later, and its stop() bailed out with FAIL when the pidfile was missing, so restart could not recover a thttpd that was running without one. Fall back to killall in that case, and never signal a recorded pid that is no longer alive since the number may have been recycled. loaderPorts compared the new port against HTTPPORT, which arc.conf had already been rewritten to hold, so the restart was skipped on a real change. Capture the running port before the rewrite.
584 lines
17 KiB
Bash
Executable File
584 lines
17 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
#
|
|
# Copyright (C) 2026 AuxXxilium <https://github.com/AuxXxilium>
|
|
#
|
|
# This is free software, licensed under the MIT License.
|
|
# See /LICENSE for more information.
|
|
#
|
|
|
|
[ -n "${1}" ] && export TOKEN="${1}"
|
|
|
|
function githubApiGet() {
|
|
local URL="${1}"
|
|
local TMP_FILE=""
|
|
|
|
TMP_FILE=$(mktemp)
|
|
if [ -n "${TOKEN}" ]; then
|
|
if ! curl -fsSL --retry 3 --retry-delay 1 --retry-all-errors -H "Accept: application/vnd.github+json" -H "Authorization: token ${TOKEN}" "${URL}" -o "${TMP_FILE}"; then
|
|
rm -f "${TMP_FILE}"
|
|
echo "GitHub API request failed: ${URL}" >&2
|
|
return 1
|
|
fi
|
|
else
|
|
if ! curl -fsSL --retry 3 --retry-delay 1 --retry-all-errors -H "Accept: application/vnd.github+json" "${URL}" -o "${TMP_FILE}"; then
|
|
rm -f "${TMP_FILE}"
|
|
echo "GitHub API request failed: ${URL}" >&2
|
|
return 1
|
|
fi
|
|
fi
|
|
|
|
if ! jq -e . >/dev/null 2>&1 <"${TMP_FILE}"; then
|
|
rm -f "${TMP_FILE}"
|
|
echo "GitHub API returned invalid JSON: ${URL}" >&2
|
|
return 1
|
|
fi
|
|
|
|
cat "${TMP_FILE}"
|
|
rm -f "${TMP_FILE}"
|
|
}
|
|
|
|
function githubLatestReleaseTag() {
|
|
local REPO="${1}"
|
|
local JSON=""
|
|
local TAG=""
|
|
|
|
JSON=$(githubApiGet "https://api.github.com/repos/AuxXxilium/${REPO}/releases") || return 1
|
|
TAG=$(jq -er '.[].tag_name // empty' <<<"${JSON}" | sort -rV | head -1) || return 1
|
|
|
|
if [ -z "${TAG}" ]; then
|
|
echo "No releases found for ${REPO}" >&2
|
|
return 1
|
|
fi
|
|
|
|
printf '%s\n' "${TAG}"
|
|
}
|
|
|
|
function githubReleaseAssets() {
|
|
local REPO="${1}"
|
|
local TAG="${2}"
|
|
local JSON=""
|
|
|
|
JSON=$(githubApiGet "https://api.github.com/repos/AuxXxilium/${REPO}/releases/tags/${TAG}") || return 1
|
|
jq -er '.assets[]? | [.id, .name] | @tsv' <<<"${JSON}"
|
|
}
|
|
|
|
function githubDownloadReleaseAsset() {
|
|
local REPO="${1}"
|
|
local TAG="${2}"
|
|
local ASSET_NAME="${3}"
|
|
local OUTPUT_FILE="${4}"
|
|
local ASSETS=""
|
|
local FOUND=0
|
|
|
|
ASSETS=$(githubReleaseAssets "${REPO}" "${TAG}") || return 1
|
|
while IFS=$'\t' read -r ID NAME; do
|
|
if [ "${NAME}" = "${ASSET_NAME}" ]; then
|
|
FOUND=1
|
|
if [ -n "${TOKEN}" ]; then
|
|
curl -fkL --retry 3 --retry-delay 1 --retry-all-errors -H "Authorization: token ${TOKEN}" -H "Accept: application/octet-stream" "https://api.github.com/repos/AuxXxilium/${REPO}/releases/assets/${ID}" -o "${OUTPUT_FILE}" || return 1
|
|
else
|
|
curl -fkL --retry 3 --retry-delay 1 --retry-all-errors -H "Accept: application/octet-stream" "https://api.github.com/repos/AuxXxilium/${REPO}/releases/assets/${ID}" -o "${OUTPUT_FILE}" || return 1
|
|
fi
|
|
break
|
|
fi
|
|
done <<< "${ASSETS}"
|
|
|
|
if [ "${FOUND}" -eq 0 ]; then
|
|
echo "No asset named ${ASSET_NAME} found for ${REPO} ${TAG}" >&2
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# Get latest LKMs
|
|
# $1 path
|
|
function getLKMs() {
|
|
echo "Getting LKMs begin"
|
|
local DEST_PATH="${1}"
|
|
local CACHE_FILE="/tmp/rp-lkms.zip"
|
|
local TAG=""
|
|
rm -f "${CACHE_FILE}"
|
|
TAG=$(githubLatestReleaseTag "arc-lkm") || return 1
|
|
export LKMTAG="${TAG}"
|
|
githubDownloadReleaseAsset "arc-lkm" "${TAG}" "rp-lkms.zip" "${CACHE_FILE}" || return 1
|
|
# Unzip LKMs
|
|
rm -rf "${DEST_PATH}"
|
|
mkdir -p "${DEST_PATH}"
|
|
if unzip -o "${CACHE_FILE}" -d "${DEST_PATH}"; then
|
|
rm -f "${CACHE_FILE}"
|
|
echo "Getting LKMs end - ${TAG}"
|
|
else
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# Get latest Addons
|
|
# $1 path
|
|
function getAddons() {
|
|
echo "Getting Addons begin"
|
|
local DEST_PATH="${1}"
|
|
local CACHE_DIR="/tmp/addons"
|
|
local CACHE_FILE="/tmp/addons.zip"
|
|
local TAG=""
|
|
rm -f "${CACHE_FILE}"
|
|
TAG=$(githubLatestReleaseTag "arc-addons") || return 1
|
|
export ADDONTAG="${TAG}"
|
|
githubDownloadReleaseAsset "arc-addons" "${TAG}" "addons-${TAG}.zip" "${CACHE_FILE}" || return 1
|
|
# Unzip Addons
|
|
rm -rf "${CACHE_DIR}"
|
|
mkdir -p "${CACHE_DIR}"
|
|
mkdir -p "${DEST_PATH}"
|
|
if unzip -o "${CACHE_FILE}" -d "${CACHE_DIR}"; then
|
|
echo "Installing Addons to ${DEST_PATH}"
|
|
[ -f /tmp/addons/VERSION ] && cp -f /tmp/addons/VERSION ${DEST_PATH}/
|
|
for PKG in $(LC_ALL=C printf '%s\n' ${CACHE_DIR}/*.addon | sort -V); do
|
|
ADDON=$(basename "${PKG}" .addon)
|
|
mkdir -p "${DEST_PATH}/${ADDON}"
|
|
echo "Extracting ${PKG} to ${DEST_PATH}/${ADDON}"
|
|
tar -xaf "${PKG}" -C "${DEST_PATH}/${ADDON}"
|
|
done
|
|
rm -f "${CACHE_FILE}"
|
|
echo "Getting Addons end - ${TAG}"
|
|
else
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# Get latest Modules
|
|
# $1 path
|
|
function getModules() {
|
|
echo "Getting Modules begin"
|
|
local DEST_PATH="${1}"
|
|
local CACHE_FILE="/tmp/modules.zip"
|
|
local TAG=""
|
|
rm -f "${CACHE_FILE}"
|
|
TAG=$(githubLatestReleaseTag "arc-modules") || return 1
|
|
export MODULETAG="${TAG}"
|
|
githubDownloadReleaseAsset "arc-modules" "${TAG}" "modules-${TAG}.zip" "${CACHE_FILE}" || return 1
|
|
# Unzip Modules
|
|
rm -rf "${DEST_PATH}"
|
|
mkdir -p "${DEST_PATH}"
|
|
if unzip -o "${CACHE_FILE}" -d "${DEST_PATH}"; then
|
|
rm -f "${CACHE_FILE}"
|
|
echo "Getting Modules end - ${TAG}"
|
|
else
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# Get latest Configs
|
|
# $1 path
|
|
function getConfigs() {
|
|
echo "Getting Configs begin"
|
|
local DEST_PATH="${1}"
|
|
local CACHE_FILE="/tmp/configs.zip"
|
|
local TAG=""
|
|
rm -f "${CACHE_FILE}"
|
|
TAG=$(githubLatestReleaseTag "arc-configs") || return 1
|
|
export CONFIGTAG="${TAG}"
|
|
githubDownloadReleaseAsset "arc-configs" "${TAG}" "configs-${TAG}.zip" "${CACHE_FILE}" || return 1
|
|
# Unzip Configs
|
|
rm -rf "${DEST_PATH}"
|
|
mkdir -p "${DEST_PATH}"
|
|
if unzip -o "${CACHE_FILE}" -d "${DEST_PATH}"; then
|
|
rm -f "${CACHE_FILE}"
|
|
echo "Getting Configs end - ${TAG}"
|
|
else
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# Get latest Patches
|
|
# $1 path
|
|
function getPatches() {
|
|
echo "Getting Patches begin"
|
|
local DEST_PATH="${1}"
|
|
local CACHE_FILE="/tmp/patches.zip"
|
|
local TAG=""
|
|
rm -f "${CACHE_FILE}"
|
|
TAG=$(githubLatestReleaseTag "arc-patches") || return 1
|
|
export PATCHTAG="${TAG}"
|
|
githubDownloadReleaseAsset "arc-patches" "${TAG}" "patches-${TAG}.zip" "${CACHE_FILE}" || return 1
|
|
# Unzip Patches
|
|
rm -rf "${DEST_PATH}"
|
|
mkdir -p "${DEST_PATH}"
|
|
if unzip -o "${CACHE_FILE}" -d "${DEST_PATH}"; then
|
|
rm -f "${CACHE_FILE}"
|
|
echo "Getting Patches end - ${TAG}"
|
|
else
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# Get latest Custom
|
|
# $1 path
|
|
function getCustom() {
|
|
echo "Getting Custom begin"
|
|
local DEST_PATH="${1}"
|
|
local CACHE_FILE="/tmp/custom.zip"
|
|
local TAG=""
|
|
rm -f "${CACHE_FILE}"
|
|
TAG=$(githubLatestReleaseTag "arc-custom") || return 1
|
|
export CUSTOMTAG="${TAG}"
|
|
githubDownloadReleaseAsset "arc-custom" "${TAG}" "custom-${TAG}.zip" "${CACHE_FILE}" || return 1
|
|
# Unzip Custom
|
|
rm -rf "${DEST_PATH}"
|
|
mkdir -p "${DEST_PATH}"
|
|
if unzip -o "${CACHE_FILE}" -d "${DEST_PATH}"; then
|
|
rm -f "${CACHE_FILE}"
|
|
echo "Getting Custom end - ${TAG}"
|
|
else
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# Get latest Theme
|
|
# $1 path
|
|
function getTheme() {
|
|
echo "Getting Theme begin"
|
|
local DEST_PATH="${1}"
|
|
local CACHE_FILE="/tmp/theme.zip"
|
|
local TAG=""
|
|
rm -f "${CACHE_FILE}"
|
|
TAG=$(githubLatestReleaseTag "arc-theme") || return 1
|
|
export THEMETAG="${TAG}"
|
|
githubDownloadReleaseAsset "arc-theme" "${TAG}" "arc-theme-${TAG}.zip" "${CACHE_FILE}" || return 1
|
|
# Unzip Theme
|
|
mkdir -p "${DEST_PATH}"
|
|
if unzip -o "${CACHE_FILE}" -d "${DEST_PATH}"; then
|
|
rm -f "${CACHE_FILE}"
|
|
echo "Getting Theme end - ${TAG}"
|
|
else
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# Get latest Buildroot
|
|
# $1 type
|
|
# $2 path
|
|
function getBuildroot() {
|
|
local TYPE="${1}"
|
|
local DEST_PATH="br"
|
|
local REPO=""
|
|
local TAG=""
|
|
[ "${TYPE}" = "apex" ] && REPO="arc-buildroot-essential"
|
|
[ "${TYPE}" = "evo" ] && REPO="arc-buildroot-evo"
|
|
|
|
echo "Getting Buildroot-${TYPE} begin"
|
|
TAG=$(githubLatestReleaseTag "${REPO}") || return 1
|
|
export "${TYPE}"="${TAG}"
|
|
[ ! -d "${DEST_PATH}" ] && mkdir -p "${DEST_PATH}"
|
|
githubDownloadReleaseAsset "${REPO}" "${TAG}" "buildroot-${TAG}.zip" "${DEST_PATH}/br-${TYPE}.zip" || return 1
|
|
echo "Buildroot: ${TAG}"
|
|
unzip -o "${DEST_PATH}/br-${TYPE}.zip" -d "${DEST_PATH}" || return 1
|
|
mv -f "${DEST_PATH}/bzImage" "${DEST_PATH}/bzImage-${TYPE}"
|
|
mv -f "${DEST_PATH}/rootfs.cpio.zst" "${DEST_PATH}/initrd-${TYPE}"
|
|
rm -f "${DEST_PATH}/br-${TYPE}.zip"
|
|
[ -f "${DEST_PATH}/bzImage-${TYPE}" ] && [ -f "${DEST_PATH}/initrd-${TYPE}" ] || return 1
|
|
}
|
|
|
|
# repack initrd
|
|
# $1 initrd file
|
|
# $2 plugin path
|
|
# $3 output file
|
|
function repackInitrd() {
|
|
local INITRD_FILE="${1}"
|
|
local PLUGIN_PATH="${2}"
|
|
local OUTPUT_PATH="${3:-${INITRD_FILE}}"
|
|
|
|
[ -z "${INITRD_FILE}" ] || [ ! -f "${INITRD_FILE}" ] && exit 1
|
|
[ -z "${PLUGIN_PATH}" ] || [ ! -d "${PLUGIN_PATH}" ] && exit 1
|
|
|
|
INITRD_FILE="$(realpath "${INITRD_FILE}")"
|
|
PLUGIN_PATH="$(realpath "${PLUGIN_PATH}")"
|
|
OUTPUT_PATH="$(realpath "${OUTPUT_PATH}")"
|
|
|
|
local RDXZ_PATH="rdxz_tmp"
|
|
mkdir -p "${RDXZ_PATH}"
|
|
local INITRD_FORMAT=$(file -b --mime-type "${INITRD_FILE}")
|
|
|
|
case "${INITRD_FORMAT}" in
|
|
*'x-cpio'*) (cd "${RDXZ_PATH}" && sudo cpio -idm <"${INITRD_FILE}") >/dev/null 2>&1 ;;
|
|
*'x-xz'*) (cd "${RDXZ_PATH}" && xz -dc "${INITRD_FILE}" | sudo cpio -idm) >/dev/null 2>&1 ;;
|
|
*'x-lz4'*) (cd "${RDXZ_PATH}" && lz4 -dc "${INITRD_FILE}" | sudo cpio -idm) >/dev/null 2>&1 ;;
|
|
*'x-lzma'*) (cd "${RDXZ_PATH}" && lzma -dc "${INITRD_FILE}" | sudo cpio -idm) >/dev/null 2>&1 ;;
|
|
*'x-bzip2'*) (cd "${RDXZ_PATH}" && bzip2 -dc "${INITRD_FILE}" | sudo cpio -idm) >/dev/null 2>&1 ;;
|
|
*'gzip'*) (cd "${RDXZ_PATH}" && gzip -dc "${INITRD_FILE}" | sudo cpio -idm) >/dev/null 2>&1 ;;
|
|
*'zstd'*) (cd "${RDXZ_PATH}" && zstd -dc "${INITRD_FILE}" | sudo cpio -idm) >/dev/null 2>&1 ;;
|
|
*) ;;
|
|
esac
|
|
|
|
sudo cp -rfp "${PLUGIN_PATH}/"* "${RDXZ_PATH}/"
|
|
|
|
# Remove ttyd and dufs autostart scripts (services now start via web login)
|
|
sudo rm -f "${RDXZ_PATH}/etc/init.d/S99ttyd"
|
|
sudo rm -f "${RDXZ_PATH}/etc/init.d/S99dufs"
|
|
|
|
# Update S90thttpd to run as root with CGI support for web authentication
|
|
sudo tee "${RDXZ_PATH}/etc/init.d/S90thttpd" >/dev/null <<'EOF'
|
|
#!/bin/sh
|
|
|
|
DAEMON="thttpd"
|
|
PIDFILE="/var/run/$DAEMON.pid"
|
|
HTTPPORT=$(grep -i '^HTTP_PORT=' /etc/arc.conf 2>/dev/null | cut -d'=' -f2)
|
|
HTTPPORT=${HTTPPORT:-7080}
|
|
|
|
start() {
|
|
printf 'Starting %s: ' "$DAEMON"
|
|
# Run as root with CGI support for authentication
|
|
/usr/sbin/thttpd -h 0.0.0.0 -p ${HTTPPORT} -d /var/www/data -u root -c '**.cgi' -i "$PIDFILE" 2>/dev/null
|
|
status=$?
|
|
if [ "$status" -eq 0 ]; then
|
|
echo "OK"
|
|
else
|
|
echo "FAIL"
|
|
fi
|
|
return "$status"
|
|
}
|
|
|
|
stop() {
|
|
printf 'Stopping %s: ' "$DAEMON"
|
|
# Only signal the recorded pid if it is still ours, the pid file outlives a
|
|
# crashed thttpd and the number may have been recycled by then
|
|
if [ -f "$PIDFILE" ] && kill -0 "$(cat "$PIDFILE" 2>/dev/null)" 2>/dev/null; then
|
|
kill "$(cat "$PIDFILE")" 2>/dev/null
|
|
else
|
|
killall "$DAEMON" 2>/dev/null
|
|
fi
|
|
rm -f "$PIDFILE"
|
|
echo "OK"
|
|
}
|
|
|
|
restart() {
|
|
stop
|
|
sleep 1
|
|
start
|
|
}
|
|
|
|
case "$1" in
|
|
start | stop | restart)
|
|
"$1"
|
|
;;
|
|
reload)
|
|
restart
|
|
;;
|
|
*)
|
|
echo "Usage: $0 {start|stop|restart|reload}"
|
|
exit 1
|
|
;;
|
|
esac
|
|
EOF
|
|
sudo chmod +x "${RDXZ_PATH}/etc/init.d/S90thttpd"
|
|
|
|
[ -f "${OUTPUT_PATH}" ] && rm -rf "${OUTPUT_PATH}"
|
|
|
|
case "${INITRD_FORMAT}" in
|
|
*'x-cpio'*) (cd "${RDXZ_PATH}" && sudo find . 2>/dev/null | sudo cpio -o -H newc -R root:root >"${OUTPUT_PATH}") >/dev/null 2>&1 ;;
|
|
*'x-xz'*) (cd "${RDXZ_PATH}" && sudo find . 2>/dev/null | sudo cpio -o -H newc -R root:root | xz -9 -C crc32 -c - >"${OUTPUT_PATH}") >/dev/null 2>&1 ;;
|
|
*'x-lz4'*) (cd "${RDXZ_PATH}" && sudo find . 2>/dev/null | sudo cpio -o -H newc -R root:root | lz4 -9 -l -c - >"${OUTPUT_PATH}") >/dev/null 2>&1 ;;
|
|
*'x-lzma'*) (cd "${RDXZ_PATH}" && sudo find . 2>/dev/null | sudo cpio -o -H newc -R root:root | lzma -9 -c - >"${OUTPUT_PATH}") >/dev/null 2>&1 ;;
|
|
*'x-bzip2'*) (cd "${RDXZ_PATH}" && sudo find . 2>/dev/null | sudo cpio -o -H newc -R root:root | bzip2 -9 -c - >"${OUTPUT_PATH}") >/dev/null 2>&1 ;;
|
|
*'gzip'*) (cd "${RDXZ_PATH}" && sudo find . 2>/dev/null | sudo cpio -o -H newc -R root:root | gzip -9 -c - >"${OUTPUT_PATH}") >/dev/null 2>&1 ;;
|
|
*'zstd'*) (cd "${RDXZ_PATH}" && sudo find . 2>/dev/null | sudo cpio -o -H newc -R root:root | zstd -19 -T0 -f -c - >"${OUTPUT_PATH}") >/dev/null 2>&1 ;;
|
|
*) ;;
|
|
esac
|
|
sudo rm -rf "${RDXZ_PATH}"
|
|
}
|
|
|
|
# resizeimg
|
|
# $1 input file
|
|
# $2 changsize MB eg: +50M -50M
|
|
# $3 output file
|
|
function resizeImg() {
|
|
local INPUT_FILE="${1}"
|
|
local CHANGE_SIZE="${2}"
|
|
local OUTPUT_FILE="${3:-${INPUT_FILE}}"
|
|
|
|
[ -z "${INPUT_FILE}" ] || [ ! -f "${INPUT_FILE}" ] && exit 1
|
|
[ -z "${CHANGE_SIZE}" ] && exit 1
|
|
|
|
INPUT_FILE="$(realpath "${INPUT_FILE}")"
|
|
OUTPUT_FILE="$(realpath "${OUTPUT_FILE}")"
|
|
|
|
local SIZE=$(($(du -sm "${INPUT_FILE}" 2>/dev/null | awk '{print $1}')$(echo "${CHANGE_SIZE}" | sed 's/M//g; s/b//g')))
|
|
[ "${SIZE:-0}" -lt 0 ] && exit 1
|
|
|
|
if [ ! "${INPUT_FILE}" = "${OUTPUT_FILE}" ]; then
|
|
sudo cp -f "${INPUT_FILE}" "${OUTPUT_FILE}"
|
|
fi
|
|
|
|
sudo truncate -s ${SIZE}M "${OUTPUT_FILE}"
|
|
echo -e "d\n\nn\n\n\n\n\nn\nw" | sudo fdisk "${OUTPUT_FILE}" >/dev/null 2>&1
|
|
local LOOPX LOOPXPY
|
|
LOOPX=$(sudo losetup -f)
|
|
sudo losetup -P "${LOOPX}" "${OUTPUT_FILE}"
|
|
LOOPXPY="$(find "${LOOPX}p"* -maxdepth 0 2>/dev/null | sort -n | tail -1)"
|
|
sudo e2fsck -fp "${LOOPXPY:-${LOOPX}p3}"
|
|
sudo resize2fs "${LOOPXPY:-${LOOPX}p3}"
|
|
sudo losetup -d "${LOOPX}"
|
|
}
|
|
|
|
# createvmx
|
|
# $1 bootloader file
|
|
# $2 vmx name
|
|
function createvmx() {
|
|
BLIMAGE=${1}
|
|
VMNAME=${2}
|
|
|
|
if ! type -p qemu-img >/dev/null 2>&1; then
|
|
sudo apt install -y qemu-utils
|
|
fi
|
|
|
|
# Convert raw image to VMDK
|
|
rm -rf "VMX_${VMNAME}"
|
|
mkdir -p "VMX_${VMNAME}"
|
|
qemu-img convert -O vmdk -o 'adapter_type=lsilogic,subformat=monolithicSparse,compat6' "${BLIMAGE}" "VMX_${VMNAME}/${VMNAME}-disk1.vmdk"
|
|
qemu-img create -f vmdk "VMX_${VMNAME}/${VMNAME}-disk2.vmdk" "32G"
|
|
|
|
# Create VM configuration
|
|
cat <<_EOF_ >"VMX_${VMNAME}/${VMNAME}.vmx"
|
|
.encoding = "UTF-8"
|
|
config.version = "8"
|
|
virtualHW.version = "17"
|
|
displayName = "${VMNAME}"
|
|
annotation = "https://github.com/AuxXxilium/arc"
|
|
guestOS = "ubuntu-64"
|
|
firmware = "efi"
|
|
mks.enable3d = "TRUE"
|
|
pciBridge0.present = "TRUE"
|
|
pciBridge4.present = "TRUE"
|
|
pciBridge4.virtualDev = "pcieRootPort"
|
|
pciBridge4.functions = "8"
|
|
pciBridge5.present = "TRUE"
|
|
pciBridge5.virtualDev = "pcieRootPort"
|
|
pciBridge5.functions = "8"
|
|
pciBridge6.present = "TRUE"
|
|
pciBridge6.virtualDev = "pcieRootPort"
|
|
pciBridge6.functions = "8"
|
|
pciBridge7.present = "TRUE"
|
|
pciBridge7.virtualDev = "pcieRootPort"
|
|
pciBridge7.functions = "8"
|
|
vmci0.present = "TRUE"
|
|
hpet0.present = "TRUE"
|
|
nvram = "${VMNAME}.nvram"
|
|
virtualHW.productCompatibility = "hosted"
|
|
powerType.powerOff = "soft"
|
|
powerType.powerOn = "soft"
|
|
powerType.suspend = "soft"
|
|
powerType.reset = "soft"
|
|
tools.syncTime = "FALSE"
|
|
sound.autoDetect = "TRUE"
|
|
sound.fileName = "-1"
|
|
sound.present = "TRUE"
|
|
numvcpus = "2"
|
|
cpuid.coresPerSocket = "1"
|
|
vcpu.hotadd = "TRUE"
|
|
memsize = "4096"
|
|
mem.hotadd = "TRUE"
|
|
usb.present = "TRUE"
|
|
ehci.present = "TRUE"
|
|
usb_xhci.present = "TRUE"
|
|
svga.graphicsMemoryKB = "8388608"
|
|
usb.vbluetooth.startConnected = "TRUE"
|
|
extendedConfigFile = "${VMNAME}.vmxf"
|
|
floppy0.present = "FALSE"
|
|
ethernet0.addressType = "generated"
|
|
ethernet0.virtualDev = "vmxnet3"
|
|
ethernet0.connectionType = "nat"
|
|
ethernet0.allowguestconnectioncontrol = "true"
|
|
ethernet0.present = "TRUE"
|
|
serial0.fileType = "file"
|
|
serial0.fileName = "serial0.log"
|
|
serial0.present = "TRUE"
|
|
sata0.present = "TRUE"
|
|
sata0:0.fileName = "${VMNAME}-disk1.vmdk"
|
|
sata0:0.present = "TRUE"
|
|
sata0:1.fileName = "${VMNAME}-disk2.vmdk"
|
|
sata0:1.present = "TRUE"
|
|
_EOF_
|
|
}
|
|
|
|
# convertvmx
|
|
# $1 bootloader file
|
|
# $2 vmx file
|
|
function convertvmx() {
|
|
local BLIMAGE=${1}
|
|
local VMXPATH=${2}
|
|
|
|
BLIMAGE="$(realpath "${BLIMAGE}")"
|
|
VMXPATH="$(realpath "${VMXPATH}")"
|
|
local VMNAME="$(basename "${VMXPATH}" .vmx)"
|
|
|
|
createvmx "${BLIMAGE}" "${VMNAME}"
|
|
|
|
rm -rf "${VMXPATH}"
|
|
mv -f "VMX_${VMNAME}" "${VMXPATH}"
|
|
}
|
|
|
|
# convertova
|
|
# $1 bootloader file
|
|
# $2 ova file
|
|
function convertova() {
|
|
local BLIMAGE=${1}
|
|
local OVAPATH=${2}
|
|
|
|
BLIMAGE="$(realpath "${BLIMAGE}")"
|
|
OVAPATH="$(realpath "${OVAPATH}")"
|
|
local VMNAME="$(basename "${OVAPATH}" .ova)"
|
|
|
|
createvmx "${BLIMAGE}" "${VMNAME}"
|
|
|
|
# Download and install ovftool if it doesn't exist
|
|
if [ ! -x ovftool/ovftool ]; then
|
|
rm -rf ovftool ovftool.zip
|
|
curl -skL https://github.com/rgl/ovftool-binaries/raw/main/archive/VMware-ovftool-4.6.3-24031167-lin.x86_64.zip -o ovftool.zip
|
|
if [ $? -ne 0 ]; then
|
|
echo "Failed to download ovftool"
|
|
exit 1
|
|
fi
|
|
unzip ovftool.zip -d . >/dev/null 2>&1
|
|
if [ $? -ne 0 ]; then
|
|
echo "Failed to extract ovftool"
|
|
exit 1
|
|
fi
|
|
chmod +x ovftool/ovftool
|
|
fi
|
|
|
|
rm -f "${OVAPATH}"
|
|
ovftool/ovftool "VMX_${VMNAME}/${VMNAME}.vmx" "${OVAPATH}"
|
|
rm -rf "VMX_${VMNAME}"
|
|
}
|
|
|
|
# createvmc
|
|
# $1 vhd file
|
|
# $2 vmc file
|
|
function createvmc() {
|
|
local BLIMAGE=${1:-arc.vhd}
|
|
local VMCPATH=${2:-arc.vmc}
|
|
|
|
BLIMAGE="$(basename "${BLIMAGE}")"
|
|
VMCPATH="$(realpath "${VMCPATH}")"
|
|
|
|
cat <<_EOF_ >"${VMCPATH}"
|
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
<preferences>
|
|
<version type="string">2.0</version>
|
|
<hardware>
|
|
<memory>
|
|
<ram_size type="integer">4096</ram_size>
|
|
</memory>
|
|
<pci_bus>
|
|
<ide_adapter>
|
|
<ide_controller id="0">
|
|
<location id="0">
|
|
<drive_type type="integer">1</drive_type>
|
|
<pathname>
|
|
<relative type="string">${BLIMAGE}</relative>
|
|
</pathname>
|
|
</location>
|
|
</ide_controller>
|
|
</ide_adapter>
|
|
</pci_bus>
|
|
</hardware>
|
|
</preferences>
|
|
_EOF_
|
|
} |