build: Refactor shared code (#220)

This commit is contained in:
Kroese 2025-03-20 02:49:36 +01:00 committed by GitHub
parent 226ecd081a
commit ad2458ea42
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 10 additions and 2152 deletions

View file

@ -1,3 +1,6 @@
ARG VERSION_ARG="latest"
FROM qemux/qemu:${VERSION_ARG} AS src
FROM debian:trixie-slim
ARG VERSION_ARG="0.0"
@ -46,15 +49,12 @@ RUN set -eu && \
echo "$VERSION_ARG" > /run/version && \
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
COPY --chmod=755 ./src /run/
COPY --from=src /run/*.sh /run
COPY --from=src /var/www /var/www
COPY --from=src /usr/share/novnc /usr/share/novnc
COPY --from=src /etc/nginx/sites-enabled /etc/nginx/sites-enabled
ADD --chmod=664 https://raw.githubusercontent.com/qemus/qemu/master/web/index.html /var/www/index.html
ADD --chmod=664 https://raw.githubusercontent.com/qemus/qemu/master/web/js/script.js /var/www/js/script.js
ADD --chmod=664 https://raw.githubusercontent.com/qemus/qemu/master/web/css/style.css /var/www/css/style.css
ADD --chmod=664 https://raw.githubusercontent.com/qemus/qemu/master/web/img/favicon.svg /var/www/img/favicon.svg
ADD --chmod=664 https://raw.githubusercontent.com/qemus/qemu/master/web/conf/defaults.json /usr/share/novnc
ADD --chmod=664 https://raw.githubusercontent.com/qemus/qemu/master/web/conf/mandatory.json /usr/share/novnc
ADD --chmod=744 https://raw.githubusercontent.com/qemus/qemu/master/web/conf/nginx.conf /etc/nginx/sites-enabled/web.conf
COPY --chmod=755 ./src /run/
VOLUME /storage
EXPOSE 22 5900 8006

View file

@ -67,7 +67,7 @@ if [[ "$RAM_CHECK" != [Nn]* ]]; then
fi
if [[ "$DEBUG" == [Yy1]* ]]; then
printf "Arguments:\n\n%s" "${ARGS// -/$'\n-'}" && echo
printf "Arguments:\n\n%s\n\n" "${ARGS// -/$'\n-'}"
fi
return 0

View file

@ -1,224 +0,0 @@
#!/usr/bin/env bash
set -Eeuo pipefail
pipe() {
local code="99"
msg="Failed to connect to $1, reason:"
curl --disable --silent --max-time 10 --fail --location "${1}" || {
code="$?"
}
case "${code,,}" in
"6" ) error "$msg could not resolve host!" ;;
"7" ) error "$msg no internet connection available!" ;;
"28" ) error "$msg connection timed out!" ;;
"99" ) return 0 ;;
*) error "$msg $code" ;;
esac
return 1
}
getURL() {
local id="${1/ /}"
local ret="$2"
local url=""
local arm=""
local name=""
local body=""
local version=""
case "${id,,}" in
"alma" | "almalinux" | "alma-linux" )
name="AlmaLinux"
if [[ "$ret" == "url" ]]; then
url="https://repo.almalinux.org/almalinux/9/live/x86_64/AlmaLinux-9-latest-x86_64-Live-GNOME.iso"
arm="https://repo.almalinux.org/almalinux/9/live/aarch64/AlmaLinux-9-latest-aarch64-Live-GNOME.iso"
fi ;;
"alpine" | "alpinelinux" | "alpine-linux" )
name="Alpine Linux"
if [[ "$ret" == "url" ]]; then
body=$(pipe "https://dl-cdn.alpinelinux.org/alpine/latest-stable/releases/x86_64/latest-releases.yaml") || exit 65
version=$(echo "$body" | awk '/"Xen"/{found=0} {if(found) print} /"Virtual"/{found=1}' | grep 'version:' | awk '{print $2}')
url="https://dl-cdn.alpinelinux.org/alpine/latest-stable/releases/x86_64/alpine-virt-$version-x86_64.iso"
arm="https://dl-cdn.alpinelinux.org/alpine/latest-stable/releases/aarch64/alpine-virt-$version-aarch64.iso"
fi ;;
"arch" | "archlinux" | "arch-linux" )
name="Arch Linux"
if [[ "$ret" == "url" ]]; then
url="https://geo.mirror.pkgbuild.com/iso/latest/archlinux-x86_64.iso"
fi ;;
"cachy" | "cachyos" )
name="CachyOS"
if [[ "$ret" == "url" ]]; then
body=$(pipe "https://cachyos.org/download/") || exit 65
url=$(echo "$body" | tr '&' '\n' | grep "ISO/desktop" | grep -v 'iso.sha' | grep -v 'iso.sig' | cut -d';' -f2)
arm=$(echo "$body" | tr '&' '\n' | grep "ISO/handheld" | grep -v 'iso.sha' | grep -v 'iso.sig' | cut -d';' -f2)
fi ;;
"centos" | "centosstream" | "centos-stream" )
name="CentOS Stream"
if [[ "$ret" == "url" ]]; then
body=$(pipe "https://linuxsoft.cern.ch/centos-stream/") || exit 65
version=$(echo "$body" | grep "\-stream" | cut -d'"' -f 6 | cut -d'-' -f 1 | head -n 1)
url="https://mirrors.xtom.de/centos-stream/$version-stream/BaseOS/x86_64/iso/CentOS-Stream-$version-latest-x86_64-dvd1.iso"
arm="https://mirrors.xtom.de/centos-stream/$version-stream/BaseOS/aarch64/iso/CentOS-Stream-$version-latest-aarch64-dvd1.iso"
fi ;;
"debian" )
name="Debian"
if [[ "$ret" == "url" ]]; then
body=$(pipe "https://cdimage.debian.org/debian-cd/") || exit 65
version=$(echo "$body" | grep '\.[0-9]/' | cut -d'>' -f 9 | cut -d'/' -f 1)
url="https://cdimage.debian.org/debian-cd/current-live/amd64/iso-hybrid/debian-live-$version-amd64-standard.iso"
arm="https://cdimage.debian.org/debian-cd/current/arm64/iso-dvd/debian-$version-arm64-DVD-1.iso"
fi ;;
"fedora" | "fedoralinux" | "fedora-linux" )
name="Fedora Linux"
if [[ "$ret" == "url" ]]; then
body=$(pipe "https://getfedora.org/releases.json") || exit 65
version=$(echo "$body" | jq -r 'map(.version) | unique | .[]' | sed 's/ /_/g' | sort -r | head -n 1)
url=$(echo "$body" | jq -r "map(select(.arch==\"x86_64\" and .version==\"${version}\" and .variant==\"Workstation\" and .subvariant==\"Workstation\" )) | .[].link")
arm=$(echo "$body" | jq -r "map(select(.arch==\"aarch64\" and .version==\"${version}\" and .variant==\"Workstation\" and .subvariant==\"Workstation\" )) | .[].link")
fi ;;
"gentoo" | "gentoolinux" | "gentoo-linux" )
name="Gentoo Linux"
if [[ "$ret" == "url" ]]; then
if [[ "${ARCH,,}" != "arm64" ]]; then
body=$(pipe "https://mirror.bytemark.co.uk/gentoo/releases/amd64/autobuilds/latest-iso.txt") || exit 65
version=$(echo "$body" | grep livegui | cut -d' ' -f1)
url="https://distfiles.gentoo.org/releases/amd64/autobuilds/$version"
else
body=$(pipe "https://mirror.bytemark.co.uk/gentoo/releases/arm64/autobuilds/latest-qcow2.txt") || exit 65
version=$(echo "$body" | grep cloudinit | cut -d' ' -f1)
arm="https://distfiles.gentoo.org/releases/arm64/autobuilds/$version"
fi
fi ;;
"kali" | "kalilinux" | "kali-linux" )
name="Kali Linux"
if [[ "$ret" == "url" ]]; then
body=$(pipe "https://cdimage.kali.org/current/?C=M;O=D") || exit 65
version=$(echo "$body" | grep -o ">kali-linux-.*-live-amd64.iso" | head -n 1 | cut -c 2-)
url="https://cdimage.kali.org/current/$version"
version=$(echo "$body" | grep -o ">kali-linux-.*-live-arm64.iso" | head -n 1 | cut -c 2-)
arm="https://cdimage.kali.org/current/$version"
fi ;;
"kubuntu" )
name="Kubuntu"
if [[ "$ret" == "url" ]]; then
url="https://cdimage.ubuntu.com/kubuntu/releases/24.10/release/kubuntu-24.10-desktop-amd64.iso"
fi ;;
"lmde" )
name="Linux Mint Debian Edition"
if [[ "$ret" == "url" ]]; then
url="https://mirror.rackspace.com/linuxmint/iso/debian/lmde-6-cinnamon-64bit.iso"
fi ;;
"macos" | "osx" )
name="macOS"
error "To install $name use: https://github.com/dockur/macos" && return 1 ;;
"mint" | "linuxmint" | "linux-mint" )
name="Linux Mint"
if [[ "$ret" == "url" ]]; then
url="https://mirrors.layeronline.com/linuxmint/stable/22.1/linuxmint-22.1-cinnamon-64bit.iso"
fi ;;
"manjaro" )
name="Manjaro"
if [[ "$ret" == "url" ]]; then
body=$(pipe "https://gitlab.manjaro.org/web/iso-info/-/raw/master/file-info.json") || exit 65
url=$(echo "$body" | jq -r .official.plasma.image)
fi ;;
"mx" | "mxlinux" | "mx-linux" )
name="MX Linux"
if [[ "$ret" == "url" ]]; then
version=$(curl --disable -Ils "https://sourceforge.net/projects/mx-linux/files/latest/download" | grep -i 'location:' | cut -d? -f1 | cut -d_ -f1 | cut -d- -f3) || exit 65
url="https://mirror.umd.edu/mxlinux-iso/MX/Final/Xfce/MX-${version}_x64.iso"
fi ;;
"nixos" )
name="NixOS"
if [[ "$ret" == "url" ]]; then
body=$(pipe "https://nix-channels.s3.amazonaws.com/?delimiter=/") || exit 65
version=$(echo "$body" | grep -o -E 'nixos-[[:digit:]]+\.[[:digit:]]+' | cut -d- -f2 | sort -nru | head -n 1)
url="https://channels.nixos.org/nixos-$version/latest-nixos-gnome-x86_64-linux.iso"
arm="https://channels.nixos.org/nixos-$version/latest-nixos-gnome-aarch64-linux.iso"
fi ;;
"opensuse" | "open-suse" | "suse" )
name="OpenSUSE"
if [[ "$ret" == "url" ]]; then
body=$(pipe "https://download.opensuse.org/distribution/leap/") || exit 65
version=$(echo "$body" | grep 'class="name"' | cut -d '/' -f2 | grep -v 42 | sort -r | head -n 1)
url="https://download.opensuse.org/distribution/leap/$version/installer/iso/agama-installer-Leap.x86_64-Leap.iso"
arm="https://download.opensuse.org/distribution/leap/$version/installer/iso/agama-installer-Leap.aarch64-Leap.iso"
fi ;;
"oracle" | "oraclelinux" | "oracle-linux" )
name="Oracle Linux"
if [[ "$ret" == "url" ]]; then
url="https://yum.oracle.com/ISOS/OracleLinux/OL9/u5/x86_64/OracleLinux-R9-U5-x86_64-boot.iso"
arm="https://yum.oracle.com/ISOS/OracleLinux/OL9/u5/aarch64/OracleLinux-R9-U5-aarch64-boot-uek.iso"
fi ;;
"rocky" | "rockylinux" | "rocky-linux" )
name="Rocky Linux"
if [[ "$ret" == "url" ]]; then
url="https://dl.rockylinux.org/pub/rocky/9/live/x86_64/Rocky-9-Workstation-x86_64-latest.iso"
arm="https://dl.rockylinux.org/pub/rocky/9/live/aarch64/Rocky-9-Workstation-aarch64-latest.iso"
fi ;;
"slack" | "slackware" )
name="Slackware"
if [[ "$ret" == "url" ]]; then
url="https://slackware.nl/slackware-live/slackware64-current-live/slackware64-live-current.iso"
fi ;;
"tails" )
name="Tails"
if [[ "$ret" == "url" ]]; then
body=$(pipe "https://tails.net/install/v2/Tails/amd64/stable/latest.json") || exit 65
url=$(echo "$body" | jq -r '.installations[0]."installation-paths"[]|select(.type=="iso")|."target-files"[0].url')
fi ;;
"ubuntu" | "ubuntu-desktop" )
name="Ubuntu Desktop"
if [[ "$ret" == "url" ]]; then
url="https://releases.ubuntu.com/24.04.2/ubuntu-24.04.2-desktop-amd64.iso"
arm="https://cdimage.ubuntu.com/ubuntu/releases/24.10/release/ubuntu-24.10-desktop-arm64.iso"
fi ;;
"ubuntus" | "ubuntu-server")
name="Ubuntu Server"
if [[ "$ret" == "url" ]]; then
url="https://releases.ubuntu.com/24.04.2/ubuntu-24.04.2-live-server-amd64.iso"
arm="https://cdimage.ubuntu.com/releases/24.04/release/ubuntu-24.04.2-live-server-arm64.iso"
fi ;;
"windows" )
name="Windows"
error "To install $name use: https://github.com/dockur/windows" && return 1 ;;
"xubuntu" )
name="Xubuntu"
if [[ "$ret" == "url" ]]; then
url="https://mirror.us.leaseweb.net/ubuntu-cdimage/xubuntu/releases/24.04/release/xubuntu-24.04.2-desktop-amd64.iso"
fi ;;
esac
case "${ret,,}" in
"name" )
echo "$name"
;;
"url" )
if [[ "${ARCH,,}" != "arm64" ]]; then
if [ -n "$name" ] && [ -z "$url" ]; then
error "No image for $name available!"
return 1
fi
else
if [ -n "$name" ] && [ -z "$arm" ]; then
error "No image for $name is available for ARM64 yet! "
return 1
fi
fi
if [[ "${ARCH,,}" != "arm64" ]]; then
echo "$url"
else
echo "$arm"
fi ;;
esac
return 0
}
return 0

View file

@ -1,683 +0,0 @@
#!/usr/bin/env bash
set -Eeuo pipefail
# Docker environment variables
: "${DISK_IO:="native"}" # I/O Mode, can be set to 'native', 'threads' or 'io_uring'
: "${DISK_FMT:=""}" # Disk file format, can be set to "raw" (default) or "qcow2"
: "${DISK_TYPE:=""}" # Device type to be used, "sata", "nvme", "blk" or "scsi"
: "${DISK_FLAGS:=""}" # Specifies the options for use with the qcow2 disk format
: "${DISK_CACHE:="none"}" # Caching mode, can be set to 'writeback' for better performance
: "${DISK_DISCARD:="on"}" # Controls whether unmap (TRIM) commands are passed to the host.
: "${DISK_ROTATION:="1"}" # Rotation rate, set to 1 for SSD storage and increase for HDD
fmt2ext() {
local DISK_FMT=$1
case "${DISK_FMT,,}" in
qcow2)
echo "qcow2"
;;
raw)
echo "img"
;;
*)
error "Unrecognized disk format: $DISK_FMT" && exit 78
;;
esac
}
ext2fmt() {
local DISK_EXT=$1
case "${DISK_EXT,,}" in
qcow2)
echo "qcow2"
;;
img)
echo "raw"
;;
*)
error "Unrecognized file extension: .$DISK_EXT" && exit 78
;;
esac
}
getSize() {
local DISK_FILE=$1
local DISK_EXT DISK_FMT
DISK_EXT=$(echo "${DISK_FILE//*./}" | sed 's/^.*\.//')
DISK_FMT=$(ext2fmt "$DISK_EXT")
case "${DISK_FMT,,}" in
raw)
stat -c%s "$DISK_FILE"
;;
qcow2)
qemu-img info "$DISK_FILE" -f "$DISK_FMT" | grep '^virtual size: ' | sed 's/.*(\(.*\) bytes)/\1/'
;;
*)
error "Unrecognized disk format: $DISK_FMT" && exit 78
;;
esac
}
isCow() {
local FS=$1
if [[ "${FS,,}" == "btrfs" ]]; then
return 0
fi
return 1
}
supportsDirect() {
local FS=$1
if [[ "${FS,,}" == "ecryptfs" ]] || [[ "${FS,,}" == "tmpfs" ]]; then
return 1
fi
return 0
}
createDisk() {
local DISK_FILE=$1
local DISK_SPACE=$2
local DISK_DESC=$3
local DISK_FMT=$4
local FS=$5
local DATA_SIZE DIR SPACE GB FA
DATA_SIZE=$(numfmt --from=iec "$DISK_SPACE")
rm -f "$DISK_FILE"
if [[ "$ALLOCATE" != [Nn]* ]]; then
# Check free diskspace
DIR=$(dirname "$DISK_FILE")
SPACE=$(df --output=avail -B 1 "$DIR" | tail -n 1)
if (( DATA_SIZE > SPACE )); then
GB=$(formatBytes "$SPACE")
error "Not enough free space to create a $DISK_DESC of ${DISK_SPACE/G/ GB} in $DIR, it has only $GB available..."
error "Please specify a smaller ${DISK_DESC^^}_SIZE or disable preallocation by setting ALLOCATE=N." && exit 76
fi
fi
html "Creating a $DISK_DESC image..."
info "Creating a ${DISK_SPACE/G/ GB} $DISK_STYLE $DISK_DESC image in $DISK_FMT format..."
local FAIL="Could not create a $DISK_STYLE $DISK_FMT $DISK_DESC image of ${DISK_SPACE/G/ GB} ($DISK_FILE)"
case "${DISK_FMT,,}" in
raw)
if isCow "$FS"; then
if ! touch "$DISK_FILE"; then
error "$FAIL" && exit 77
fi
{ chattr +C "$DISK_FILE"; } || :
fi
if [[ "$ALLOCATE" == [Nn]* ]]; then
# Create an empty file
if ! truncate -s "$DATA_SIZE" "$DISK_FILE"; then
rm -f "$DISK_FILE"
error "$FAIL" && exit 77
fi
else
# Create an empty file
if ! fallocate -l "$DATA_SIZE" "$DISK_FILE" &>/dev/null; then
if ! fallocate -l -x "$DATA_SIZE" "$DISK_FILE"; then
if ! truncate -s "$DATA_SIZE" "$DISK_FILE"; then
rm -f "$DISK_FILE"
error "$FAIL" && exit 77
fi
fi
fi
fi
;;
qcow2)
local DISK_PARAM="$DISK_ALLOC"
isCow "$FS" && DISK_PARAM+=",nocow=on"
[ -n "$DISK_FLAGS" ] && DISK_PARAM+=",$DISK_FLAGS"
if ! qemu-img create -f "$DISK_FMT" -o "$DISK_PARAM" -- "$DISK_FILE" "$DATA_SIZE" ; then
rm -f "$DISK_FILE"
error "$FAIL" && exit 70
fi
;;
esac
if isCow "$FS"; then
FA=$(lsattr "$DISK_FILE")
if [[ "$FA" != *"C"* ]]; then
error "Failed to disable COW for $DISK_DESC image $DISK_FILE on ${FS^^} filesystem (returned $FA)"
fi
fi
return 0
}
resizeDisk() {
local DISK_FILE=$1
local DISK_SPACE=$2
local DISK_DESC=$3
local DISK_FMT=$4
local FS=$5
local CUR_SIZE DATA_SIZE DIR SPACE GB
CUR_SIZE=$(getSize "$DISK_FILE")
DATA_SIZE=$(numfmt --from=iec "$DISK_SPACE")
local REQ=$((DATA_SIZE-CUR_SIZE))
(( REQ < 1 )) && error "Shrinking disks is not supported yet, please increase ${DISK_DESC^^}_SIZE." && exit 71
if [[ "$ALLOCATE" != [Nn]* ]]; then
# Check free diskspace
DIR=$(dirname "$DISK_FILE")
SPACE=$(df --output=avail -B 1 "$DIR" | tail -n 1)
if (( REQ > SPACE )); then
GB=$(formatBytes "$SPACE")
error "Not enough free space to resize $DISK_DESC to ${DISK_SPACE/G/ GB} in $DIR, it has only $GB available.."
error "Please specify a smaller ${DISK_DESC^^}_SIZE or disable preallocation by setting ALLOCATE=N." && exit 74
fi
fi
GB=$(formatBytes "$CUR_SIZE")
MSG="Resizing $DISK_DESC from $GB to ${DISK_SPACE/G/ GB}..."
info "$MSG" && html "$MSG"
local FAIL="Could not resize the $DISK_STYLE $DISK_FMT $DISK_DESC image from ${GB} to ${DISK_SPACE/G/ GB} ($DISK_FILE)"
case "${DISK_FMT,,}" in
raw)
if [[ "$ALLOCATE" == [Nn]* ]]; then
# Resize file by changing its length
if ! truncate -s "$DATA_SIZE" "$DISK_FILE"; then
error "$FAIL" && exit 75
fi
else
# Resize file by allocating more space
if ! fallocate -l "$DATA_SIZE" "$DISK_FILE" &>/dev/null; then
if ! fallocate -l -x "$DATA_SIZE" "$DISK_FILE"; then
if ! truncate -s "$DATA_SIZE" "$DISK_FILE"; then
error "$FAIL" && exit 75
fi
fi
fi
fi
;;
qcow2)
if ! qemu-img resize -f "$DISK_FMT" "--$DISK_ALLOC" "$DISK_FILE" "$DATA_SIZE" ; then
error "$FAIL" && exit 72
fi
;;
esac
return 0
}
convertDisk() {
local SOURCE_FILE=$1
local SOURCE_FMT=$2
local DST_FILE=$3
local DST_FMT=$4
local DISK_BASE=$5
local DISK_DESC=$6
local FS=$7
[ -f "$DST_FILE" ] && error "Conversion failed, destination file $DST_FILE already exists?" && exit 79
[ ! -f "$SOURCE_FILE" ] && error "Conversion failed, source file $SOURCE_FILE does not exists?" && exit 79
local TMP_FILE="$DISK_BASE.tmp"
rm -f "$TMP_FILE"
if [[ "$ALLOCATE" != [Nn]* ]]; then
local DIR CUR_SIZE SPACE GB
# Check free diskspace
DIR=$(dirname "$TMP_FILE")
CUR_SIZE=$(getSize "$SOURCE_FILE")
SPACE=$(df --output=avail -B 1 "$DIR" | tail -n 1)
if (( CUR_SIZE > SPACE )); then
GB=$(formatBytes "$SPACE")
error "Not enough free space to convert $DISK_DESC to $DST_FMT in $DIR, it has only $GB available..."
error "Please free up some disk space or disable preallocation by setting ALLOCATE=N." && exit 76
fi
fi
local msg="Converting $DISK_DESC to $DST_FMT"
html "$msg..."
info "$msg, please wait until completed..."
local CONV_FLAGS="-p"
local DISK_PARAM="$DISK_ALLOC"
isCow "$FS" && DISK_PARAM+=",nocow=on"
if [[ "$DST_FMT" != "raw" ]]; then
if [[ "$ALLOCATE" == [Nn]* ]]; then
CONV_FLAGS+=" -c"
fi
[ -n "$DISK_FLAGS" ] && DISK_PARAM+=",$DISK_FLAGS"
fi
# shellcheck disable=SC2086
if ! qemu-img convert -f "$SOURCE_FMT" $CONV_FLAGS -o "$DISK_PARAM" -O "$DST_FMT" -- "$SOURCE_FILE" "$TMP_FILE"; then
rm -f "$TMP_FILE"
error "Failed to convert $DISK_STYLE $DISK_DESC image to $DST_FMT format in $DIR, is there enough space available?" && exit 79
fi
if [[ "$DST_FMT" == "raw" ]]; then
if [[ "$ALLOCATE" != [Nn]* ]]; then
# Work around qemu-img bug
CUR_SIZE=$(stat -c%s "$TMP_FILE")
if ! fallocate -l "$CUR_SIZE" "$TMP_FILE" &>/dev/null; then
if ! fallocate -l -x "$CUR_SIZE" "$TMP_FILE"; then
error "Failed to allocate $CUR_SIZE bytes for $DISK_DESC image $TMP_FILE"
fi
fi
fi
fi
rm -f "$SOURCE_FILE"
mv "$TMP_FILE" "$DST_FILE"
if isCow "$FS"; then
FA=$(lsattr "$DST_FILE")
if [[ "$FA" != *"C"* ]]; then
error "Failed to disable COW for $DISK_DESC image $DST_FILE on ${FS^^} filesystem (returned $FA)"
fi
fi
msg="Conversion of $DISK_DESC"
html "$msg completed..."
info "$msg to $DST_FMT completed succesfully!"
return 0
}
checkFS () {
local FS=$1
local DISK_FILE=$2
local DISK_DESC=$3
local DIR FA
DIR=$(dirname "$DISK_FILE")
[ ! -d "$DIR" ] && return 0
if [[ "${FS,,}" == "overlay"* ]]; then
info "Warning: the filesystem of $DIR is OverlayFS, this usually means it was binded to an invalid path!"
fi
if [[ "${FS,,}" == "fuse"* ]]; then
info "Warning: the filesystem of $DIR is FUSE, this extra layer will negatively affect performance!"
fi
if ! supportsDirect "$FS"; then
info "Warning: the filesystem of $DIR is $FS, which does not support O_DIRECT mode, adjusting settings..."
fi
if isCow "$FS"; then
if [ -f "$DISK_FILE" ]; then
FA=$(lsattr "$DISK_FILE")
if [[ "$FA" != *"C"* ]]; then
info "Warning: COW (copy on write) is not disabled for $DISK_DESC image file $DISK_FILE, this is recommended on ${FS^^} filesystems!"
fi
fi
fi
return 0
}
createDevice () {
local DISK_FILE=$1
local DISK_TYPE=$2
local DISK_INDEX=$3
local DISK_ADDRESS=$4
local DISK_FMT=$5
local DISK_IO=$6
local DISK_CACHE=$7
local DISK_ID="data$DISK_INDEX"
local index=""
[ -n "$DISK_INDEX" ] && index=",bootindex=$DISK_INDEX"
local result=" -drive file=$DISK_FILE,id=$DISK_ID,format=$DISK_FMT,cache=$DISK_CACHE,aio=$DISK_IO,discard=$DISK_DISCARD,detect-zeroes=on"
case "${DISK_TYPE,,}" in
"none" ) ;;
"auto" )
echo "$result"
;;
"usb" )
result+=",if=none \
-device usb-storage,drive=${DISK_ID}${index}"
echo "$result"
;;
"nvme" )
result+=",if=none \
-device nvme,drive=${DISK_ID}${index},serial=deadbeaf${DISK_INDEX}"
echo "$result"
;;
"ide" | "sata" )
result+=",if=none \
-device ich9-ahci,id=ahci${DISK_INDEX},addr=$DISK_ADDRESS \
-device ide-hd,drive=${DISK_ID},bus=ahci$DISK_INDEX.0,rotation_rate=$DISK_ROTATION${index}"
echo "$result"
;;
"blk" | "virtio-blk" )
result+=",if=none \
-device virtio-blk-pci,drive=${DISK_ID},bus=pcie.0,addr=$DISK_ADDRESS,iothread=io2${index}"
echo "$result"
;;
"scsi" | "virtio-scsi" )
result+=",if=none \
-device virtio-scsi-pci,id=${DISK_ID}b,bus=pcie.0,addr=$DISK_ADDRESS,iothread=io2 \
-device scsi-hd,drive=${DISK_ID},bus=${DISK_ID}b.0,channel=0,scsi-id=0,lun=0,rotation_rate=$DISK_ROTATION${index}"
echo "$result"
;;
esac
return 0
}
addMedia () {
local DISK_FILE=$1
local DISK_TYPE=$2
local DISK_INDEX=$3
local DISK_ADDRESS=$4
local index=""
local DISK_ID="cdrom$DISK_INDEX"
[ -n "$DISK_INDEX" ] && index=",bootindex=$DISK_INDEX"
local result=" -drive file=$DISK_FILE,id=$DISK_ID,format=raw,cache=unsafe,readonly=on,media=cdrom"
case "${DISK_TYPE,,}" in
"none" ) ;;
"auto" )
echo "$result"
;;
"usb" )
result+=",if=none \
-device usb-storage,drive=${DISK_ID}${index},removable=on"
echo "$result"
;;
"nvme" )
result+=",if=none \
-device nvme,drive=${DISK_ID}${index},serial=deadbeaf${DISK_INDEX}"
echo "$result"
;;
"ide" | "sata" )
result+=",if=none \
-device ich9-ahci,id=ahci${DISK_INDEX},addr=$DISK_ADDRESS \
-device ide-cd,drive=${DISK_ID},bus=ahci${DISK_INDEX}.0${index}"
echo "$result"
;;
"blk" | "virtio-blk" )
result+=",if=none \
-device virtio-blk-pci,drive=${DISK_ID},bus=pcie.0,addr=$DISK_ADDRESS,iothread=io2${index}"
echo "$result"
;;
"scsi" | "virtio-scsi" )
result+=",if=none \
-device virtio-scsi-pci,id=${DISK_ID}b,bus=pcie.0,addr=$DISK_ADDRESS,iothread=io2 \
-device scsi-cd,drive=${DISK_ID},bus=${DISK_ID}b.0${index}"
echo "$result"
;;
esac
return 0
}
addDisk () {
local DISK_BASE=$1
local DISK_TYPE=$2
local DISK_DESC=$3
local DISK_SPACE=$4
local DISK_INDEX=$5
local DISK_ADDRESS=$6
local DISK_FMT=$7
local DISK_IO=$8
local DISK_CACHE=$9
local DISK_EXT DIR SPACE DATA_SIZE FS PREV_FMT PREV_EXT CUR_SIZE
DISK_EXT=$(fmt2ext "$DISK_FMT")
local DISK_FILE="$DISK_BASE.$DISK_EXT"
DIR=$(dirname "$DISK_FILE")
[ ! -d "$DIR" ] && return 0
SPACE="${DISK_SPACE// /}"
[ -z "$SPACE" ] && SPACE="16G"
[ -z "${SPACE//[0-9. ]}" ] && SPACE="${SPACE}G"
SPACE=$(echo "${SPACE^^}" | sed 's/MB/M/g;s/GB/G/g;s/TB/T/g')
if ! numfmt --from=iec "$SPACE" &>/dev/null; then
error "Invalid value for ${DISK_DESC^^}_SIZE: $DISK_SPACE" && exit 73
fi
DATA_SIZE=$(numfmt --from=iec "$SPACE")
if (( DATA_SIZE < 104857600 )); then
error "Please increase ${DISK_DESC^^}_SIZE to at least 100 MB." && exit 73
fi
FS=$(stat -f -c %T "$DIR")
checkFS "$FS" "$DISK_FILE" "$DISK_DESC" || exit $?
if ! supportsDirect "$FS"; then
DISK_IO="threads"
DISK_CACHE="writeback"
fi
if ! [ -s "$DISK_FILE" ] ; then
if [[ "${DISK_FMT,,}" != "raw" ]]; then
PREV_FMT="raw"
else
PREV_FMT="qcow2"
fi
PREV_EXT=$(fmt2ext "$PREV_FMT")
if [ -s "$DISK_BASE.$PREV_EXT" ] ; then
convertDisk "$DISK_BASE.$PREV_EXT" "$PREV_FMT" "$DISK_FILE" "$DISK_FMT" "$DISK_BASE" "$DISK_DESC" "$FS" || exit $?
fi
fi
if [ -s "$DISK_FILE" ]; then
CUR_SIZE=$(getSize "$DISK_FILE")
if (( DATA_SIZE > CUR_SIZE )); then
resizeDisk "$DISK_FILE" "$SPACE" "$DISK_DESC" "$DISK_FMT" "$FS" || exit $?
fi
else
createDisk "$DISK_FILE" "$SPACE" "$DISK_DESC" "$DISK_FMT" "$FS" || exit $?
fi
DISK_OPTS+=$(createDevice "$DISK_FILE" "$DISK_TYPE" "$DISK_INDEX" "$DISK_ADDRESS" "$DISK_FMT" "$DISK_IO" "$DISK_CACHE")
return 0
}
addDevice () {
local DISK_DEV=$1
local DISK_TYPE=$2
local DISK_INDEX=$3
local DISK_ADDRESS=$4
[ -z "$DISK_DEV" ] && return 0
[ ! -b "$DISK_DEV" ] && error "Device $DISK_DEV cannot be found! Please add it to the 'devices' section of your compose file." && exit 55
DISK_OPTS+=$(createDevice "$DISK_DEV" "$DISK_TYPE" "$DISK_INDEX" "$DISK_ADDRESS" "raw" "$DISK_IO" "$DISK_CACHE")
return 0
}
html "Initializing disks..."
[ -z "${DISK_OPTS:-}" ] && DISK_OPTS=""
[ -z "${DISK_TYPE:-}" ] && DISK_TYPE="scsi"
[ -z "${DISK_NAME:-}" ] && DISK_NAME="data"
case "${DISK_TYPE,,}" in
"ide" | "sata" | "nvme" | "usb" | "scsi" | "blk" | "auto" | "none" ) ;;
* ) error "Invalid DISK_TYPE specified, value \"$DISK_TYPE\" is not recognized!" && exit 80 ;;
esac
if [[ "${MACHINE,,}" != "virt" ]]; then
FALLBACK="ide"
else
FALLBACK="usb"
fi
[[ "${BOOT_MODE:-}" == "windows_legacy" ]] && FALLBACK="auto"
if [ -z "${MEDIA_TYPE:-}" ]; then
if [[ "${BOOT_MODE:-}" != "windows"* ]]; then
if [[ "${DISK_TYPE,,}" == "blk" ]]; then
MEDIA_TYPE="$FALLBACK"
else
MEDIA_TYPE="$DISK_TYPE"
fi
else
MEDIA_TYPE="$FALLBACK"
fi
fi
case "${MEDIA_TYPE,,}" in
"ide" | "sata" | "nvme" | "usb" | "scsi" | "blk" | "auto" | "none" ) ;;
* ) error "Invalid MEDIA_TYPE specified, value \"$MEDIA_TYPE\" is not recognized!" && exit 80 ;;
esac
if [ -f "$BOOT" ] && [ -s "$BOOT" ]; then
case "${BOOT,,}" in
*".iso" )
DISK_OPTS+=$(addMedia "$BOOT" "$MEDIA_TYPE" "$BOOT_INDEX" "0x5") ;;
*".img" | *".raw" )
DISK_OPTS+=$(createDevice "$BOOT" "$DISK_TYPE" "$BOOT_INDEX" "0x5" "raw" "$DISK_IO" "$DISK_CACHE") ;;
*".qcow2" )
DISK_OPTS+=$(createDevice "$BOOT" "$DISK_TYPE" "$BOOT_INDEX" "0x5" "qcow2" "$DISK_IO" "$DISK_CACHE") ;;
* )
error "Invalid BOOT image specified, extension \".${BOOT/*./}\" is not recognized!" && exit 80 ;;
esac
fi
DRIVERS="/drivers.iso"
[ ! -f "$DRIVERS" ] || [ ! -s "$DRIVERS" ] && DRIVERS="$STORAGE/drivers.iso"
if [ -f "$DRIVERS" ] && [ -s "$DRIVERS" ]; then
DISK_OPTS+=$(addMedia "$DRIVERS" "$FALLBACK" "" "0x6")
fi
RESCUE="/start.iso"
[ ! -f "$RESCUE" ] || [ ! -s "$RESCUE" ] && RESCUE="$STORAGE/start.iso"
if [ -f "$RESCUE" ] && [ -s "$RESCUE" ]; then
DISK_OPTS+=$(addMedia "$RESCUE" "$FALLBACK" "1" "0x6")
fi
DISK1_FILE="$STORAGE/${DISK_NAME}"
DISK2_FILE="/storage2/${DISK_NAME}2"
DISK3_FILE="/storage3/${DISK_NAME}3"
DISK4_FILE="/storage4/${DISK_NAME}4"
if [ -z "$DISK_FMT" ]; then
if [ -f "$DISK1_FILE.qcow2" ]; then
DISK_FMT="qcow2"
else
DISK_FMT="raw"
fi
fi
if [ -z "$ALLOCATE" ]; then
ALLOCATE="N"
fi
if [[ "$ALLOCATE" == [Nn]* ]]; then
DISK_STYLE="growable"
DISK_ALLOC="preallocation=off"
else
DISK_STYLE="preallocated"
DISK_ALLOC="preallocation=falloc"
fi
: "${DISK2_SIZE:=""}"
: "${DISK3_SIZE:=""}"
: "${DISK4_SIZE:=""}"
: "${DEVICE:=""}" # Docker variables to passthrough a block device, like /dev/vdc1.
: "${DEVICE2:=""}"
: "${DEVICE3:=""}"
: "${DEVICE4:=""}"
[ -z "$DEVICE" ] && [ -b "/disk" ] && DEVICE="/disk"
[ -z "$DEVICE" ] && [ -b "/disk1" ] && DEVICE="/disk1"
[ -z "$DEVICE2" ] && [ -b "/disk2" ] && DEVICE2="/disk2"
[ -z "$DEVICE3" ] && [ -b "/disk3" ] && DEVICE3="/disk3"
[ -z "$DEVICE4" ] && [ -b "/disk4" ] && DEVICE4="/disk4"
[ -z "$DEVICE" ] && [ -b "/dev/disk1" ] && DEVICE="/dev/disk1"
[ -z "$DEVICE2" ] && [ -b "/dev/disk2" ] && DEVICE2="/dev/disk2"
[ -z "$DEVICE3" ] && [ -b "/dev/disk3" ] && DEVICE3="/dev/disk3"
[ -z "$DEVICE4" ] && [ -b "/dev/disk4" ] && DEVICE4="/dev/disk4"
if [ -n "$DEVICE" ]; then
addDevice "$DEVICE" "$DISK_TYPE" "3" "0xa" || exit $?
else
addDisk "$DISK1_FILE" "$DISK_TYPE" "disk" "$DISK_SIZE" "3" "0xa" "$DISK_FMT" "$DISK_IO" "$DISK_CACHE" || exit $?
fi
if [ -n "$DEVICE2" ]; then
addDevice "$DEVICE2" "$DISK_TYPE" "4" "0xb" || exit $?
else
addDisk "$DISK2_FILE" "$DISK_TYPE" "disk2" "$DISK2_SIZE" "4" "0xb" "$DISK_FMT" "$DISK_IO" "$DISK_CACHE" || exit $?
fi
if [ -n "$DEVICE3" ]; then
addDevice "$DEVICE3" "$DISK_TYPE" "5" "0xc" || exit $?
else
addDisk "$DISK3_FILE" "$DISK_TYPE" "disk3" "$DISK3_SIZE" "5" "0xc" "$DISK_FMT" "$DISK_IO" "$DISK_CACHE" || exit $?
fi
if [ -n "$DEVICE4" ]; then
addDevice "$DEVICE4" "$DISK_TYPE" "6" "0xd" || exit $?
else
addDisk "$DISK4_FILE" "$DISK_TYPE" "disk4" "$DISK4_SIZE" "6" "0xd" "$DISK_FMT" "$DISK_IO" "$DISK_CACHE" || exit $?
fi
DISK_OPTS+=" -object iothread,id=io2"
html "Initialized disks successfully..."
return 0

View file

@ -2,6 +2,7 @@
set -Eeuo pipefail
: "${APP:="QEMU"}"
: "${MACHINE:="virt"}"
: "${SUPPORT:="https://github.com/qemus/qemu-arm"}"
cd /run

View file

@ -1,344 +0,0 @@
#!/usr/bin/env bash
set -Eeuo pipefail
moveFile() {
local file="$1"
local ext="${file##*.}"
local dest="$STORAGE/boot.$ext"
if [[ "$file" == "$dest" ]] || [[ "$file" == "/boot.$ext" ]]; then
BOOT="$file"
return 0
fi
if ! mv -f "$file" "$dest"; then
error "Failed to move $file to $dest !"
return 1
fi
BOOT="$dest"
return 0
}
detectType() {
local dir=""
local file="$1"
[ ! -f "$file" ] && return 1
[ ! -s "$file" ] && return 1
case "${file,,}" in
*".iso" | *".img" | *".raw" | *".qcow2" ) ;;
* ) return 1 ;;
esac
if [ -n "$BOOT_MODE" ] || [[ "${file,,}" != *".iso" ]]; then
! moveFile "$file" && return 1
return 0
fi
# Automaticly detect UEFI-compatible ISO's
dir=$(isoinfo -f -i "$file")
if [ -n "$dir" ]; then
dir=$(echo "${dir^^}" | grep "^/EFI")
[ -z "$dir" ] && BOOT_MODE="legacy"
else
error "Failed to read ISO file, invalid format!"
fi
! moveFile "$file" && return 1
return 0
}
downloadFile() {
local url="$1"
local base="$2"
local name="$3"
local msg rc total size progress
local dest="$STORAGE/$base.tmp"
rm -f "$dest"
# Check if running with interactive TTY or redirected to docker log
if [ -t 1 ]; then
progress="--progress=bar:noscroll"
else
progress="--progress=dot:giga"
fi
if [ -z "$name" ]; then
name="$base"
msg="Downloading image"
else
msg="Downloading $name"
fi
info "Downloading $name..."
html "$msg..."
/run/progress.sh "$dest" "0" "$msg ([P])..." &
{ wget "$url" -O "$dest" -q --timeout=30 --no-http-keep-alive --show-progress "$progress"; rc=$?; } || :
fKill "progress.sh"
if (( rc == 0 )) && [ -f "$dest" ]; then
total=$(stat -c%s "$dest")
size=$(formatBytes "$total")
if [ "$total" -lt 100000 ]; then
error "Invalid image file: is only $size ?" && return 1
fi
html "Download finished successfully..."
mv -f "$dest" "$STORAGE/$base"
return 0
fi
msg="Failed to download $url"
(( rc == 3 )) && error "$msg , cannot write file (disk full?)" && return 1
(( rc == 4 )) && error "$msg , network failure!" && return 1
(( rc == 8 )) && error "$msg , server issued an error response!" && return 1
error "$msg , reason: $rc"
return 1
}
convertImage() {
local source_file=$1
local source_fmt=$2
local dst_file=$3
local dst_fmt=$4
local dir base fs fa space space_gb
local cur_size cur_gb src_size disk_param
[ -f "$dst_file" ] && error "Conversion failed, destination file $dst_file already exists?" && return 1
[ ! -f "$source_file" ] && error "Conversion failed, source file $source_file does not exists?" && return 1
if [[ "${source_fmt,,}" == "${dst_fmt,,}" ]]; then
mv -f "$source_file" "$dst_file"
return 0
fi
local tmp_file="$dst_file.tmp"
dir=$(dirname "$tmp_file")
rm -f "$tmp_file"
if [ -n "$ALLOCATE" ] && [[ "$ALLOCATE" != [Nn]* ]]; then
# Check free diskspace
src_size=$(qemu-img info "$source_file" -f "$source_fmt" | grep '^virtual size: ' | sed 's/.*(\(.*\) bytes)/\1/')
space=$(df --output=avail -B 1 "$dir" | tail -n 1)
if (( src_size > space )); then
space_gb=$(formatBytes "$space")
error "Not enough free space to convert image in $dir, it has only $space_gb available..." && return 1
fi
fi
base=$(basename "$source_file")
info "Converting $base..."
html "Converting image..."
local conv_flags="-p"
if [ -z "$ALLOCATE" ] || [[ "$ALLOCATE" == [Nn]* ]]; then
disk_param="preallocation=off"
else
disk_param="preallocation=falloc"
fi
fs=$(stat -f -c %T "$dir")
[[ "${fs,,}" == "btrfs" ]] && disk_param+=",nocow=on"
if [[ "$dst_fmt" != "raw" ]]; then
if [ -z "$ALLOCATE" ] || [[ "$ALLOCATE" == [Nn]* ]]; then
conv_flags+=" -c"
fi
[ -n "${DISK_FLAGS:-}" ] && disk_param+=",$DISK_FLAGS"
fi
# shellcheck disable=SC2086
if ! qemu-img convert -f "$source_fmt" $conv_flags -o "$disk_param" -O "$dst_fmt" -- "$source_file" "$tmp_file"; then
rm -f "$tmp_file"
error "Failed to convert image in $dir, is there enough space available?" && return 1
fi
if [[ "$dst_fmt" == "raw" ]]; then
if [ -n "$ALLOCATE" ] && [[ "$ALLOCATE" != [Nn]* ]]; then
# Work around qemu-img bug
cur_size=$(stat -c%s "$tmp_file")
cur_gb=$(formatBytes "$cur_size")
if ! fallocate -l "$cur_size" "$tmp_file" &>/dev/null; then
if ! fallocate -l -x "$cur_size" "$tmp_file"; then
error "Failed to allocate $cur_gb for image!"
fi
fi
fi
fi
rm -f "$source_file"
mv "$tmp_file" "$dst_file"
if [[ "${fs,,}" == "btrfs" ]]; then
fa=$(lsattr "$dst_file")
if [[ "$fa" != *"C"* ]]; then
error "Failed to disable COW for image on ${fs^^} filesystem!"
fi
fi
html "Conversion completed..."
return 0
}
findFile() {
local file
local ext="$1"
local fname="boot.$ext"
if [ -d "/$fname" ]; then
warn "The file /$fname has an invalid path!"
fi
file=$(find / -maxdepth 1 -type f -iname "$fname" | head -n 1)
[ ! -s "$file" ] && file=$(find "$STORAGE" -maxdepth 1 -type f -iname "$fname" | head -n 1)
detectType "$file" && return 0
return 1
}
findFile "iso" && return 0
findFile "img" && return 0
findFile "raw" && return 0
findFile "qcow2" && return 0
if [ -z "$BOOT" ] || [[ "$BOOT" == *"example.com/image.iso" ]]; then
hasDisk && return 0
error "No value specified for the BOOT variable." && exit 64
fi
url=$(getURL "$BOOT" "url") || exit 34
name=$(getURL "$BOOT" "name") || exit 34
[ -n "$url" ] && BOOT="$url"
if [[ "$BOOT" != *"."* ]]; then
error "Invalid BOOT value specified, shortcut \"$BOOT\" is not recognized!" && exit 64
fi
if [[ "${BOOT,,}" != "http"* ]]; then
error "Invalid BOOT value specified, \"$BOOT\" is not a valid URL!" && exit 64
fi
base=$(basename "${BOOT%%\?*}")
: "${base//+/ }"; printf -v base '%b' "${_//%/\\x}"
base=$(echo "$base" | sed -e 's/[^A-Za-z0-9._-]/_/g')
case "${base,,}" in
*".iso" | *".img" | *".raw" | *".qcow2" )
detectType "$STORAGE/$base" && return 0 ;;
*".vdi" | *".vmdk" | *".vhd" | *".vhdx" )
detectType "$STORAGE/${base%.*}.img" && return 0
detectType "$STORAGE/${base%.*}.qcow2" && return 0 ;;
*".gz" | *".gzip" | *".xz" | *".7z" | *".zip" | *".rar" | *".lzma" | *".bz" | *".bz2" )
case "${base%.*}" in
*".iso" | *".img" | *".raw" | *".qcow2" )
detectType "$STORAGE/${base%.*}" && return 0 ;;
*".vdi" | *".vmdk" | *".vhd" | *".vhdx" )
find="${base%.*}"
detectType "$STORAGE/${find%.*}.img" && return 0
detectType "$STORAGE/${find%.*}.qcow2" && return 0 ;;
esac ;;
* ) error "Unknown file extension, type \".${base/*./}\" is not recognized!" && exit 33 ;;
esac
if ! downloadFile "$BOOT" "$base" "$name"; then
rm -f "$STORAGE/$base.tmp" && exit 60
fi
case "${base,,}" in
*".gz" | *".gzip" | *".xz" | *".7z" | *".zip" | *".rar" | *".lzma" | *".bz" | *".bz2" )
info "Extracting $base..."
html "Extracting image..." ;;
esac
case "${base,,}" in
*".gz" | *".gzip" )
gzip -dc "$STORAGE/$base" > "$STORAGE/${base%.*}"
rm -f "$STORAGE/$base"
base="${base%.*}"
;;
*".xz" )
xz -dc "$STORAGE/$base" > "$STORAGE/${base%.*}"
rm -f "$STORAGE/$base"
base="${base%.*}"
;;
*".7z" | *".zip" | *".rar" | *".lzma" | *".bz" | *".bz2" )
tmp="$STORAGE/extract"
rm -rf "$tmp"
mkdir -p "$tmp"
7z x "$STORAGE/$base" -o"$tmp" > /dev/null
rm -f "$STORAGE/$base"
base="${base%.*}"
if [ ! -s "$tmp/$base" ]; then
rm -rf "$tmp"
error "Cannot find file \"${base}\" in .${BOOT/*./} archive!" && exit 32
fi
mv "$tmp/$base" "$STORAGE/$base"
rm -rf "$tmp"
;;
esac
case "${base,,}" in
*".iso" | *".img" | *".raw" | *".qcow2" )
detectType "$STORAGE/$base" && return 0
error "Cannot read file \"${base}\"" && exit 63 ;;
esac
target_ext="img"
target_fmt="${DISK_FMT:-}"
[ -z "$target_fmt" ] && target_fmt="raw"
[[ "$target_fmt" != "raw" ]] && target_ext="qcow2"
case "${base,,}" in
*".vdi" ) source_fmt="vdi" ;;
*".vhd" ) source_fmt="vpc" ;;
*".vhdx" ) source_fmt="vpc" ;;
*".vmdk" ) source_fmt="vmdk" ;;
* ) error "Unknown file extension, type \".${base/*./}\" is not recognized!" && exit 33 ;;
esac
dst="$STORAGE/${base%.*}.$target_ext"
! convertImage "$STORAGE/$base" "$source_fmt" "$dst" "$target_fmt" && exit 35
base=$(basename "$dst")
detectType "$STORAGE/$base" && return 0
error "Cannot convert file \"${base}\"" && exit 36

View file

@ -1,508 +0,0 @@
#!/usr/bin/env bash
set -Eeuo pipefail
# Docker environment variables
: "${MAC:=""}"
: "${MTU:=""}"
: "${DHCP:="N"}"
: "${NETWORK:="Y"}"
: "${USER_PORTS:=""}"
: "${HOST_PORTS:=""}"
: "${ADAPTER:="virtio-net-pci"}"
: "${VM_NET_DEV:=""}"
: "${VM_NET_TAP:="qemu"}"
: "${VM_NET_MAC:="$MAC"}"
: "${VM_NET_HOST:="$APP"}"
: "${VM_NET_IP:="20.20.20.21"}"
: "${DNSMASQ_OPTS:=""}"
: "${DNSMASQ:="/usr/sbin/dnsmasq"}"
: "${DNSMASQ_CONF_DIR:="/etc/dnsmasq.d"}"
ADD_ERR="Please add the following setting to your container:"
# ######################################
# Functions
# ######################################
configureDHCP() {
# Create the necessary file structure for /dev/vhost-net
if [ ! -c /dev/vhost-net ]; then
if mknod /dev/vhost-net c 10 238; then
chmod 660 /dev/vhost-net
fi
fi
# Create a macvtap network for the VM guest
{ msg=$(ip link add link "$VM_NET_DEV" name "$VM_NET_TAP" address "$VM_NET_MAC" type macvtap mode bridge 2>&1); rc=$?; } || :
case "$msg" in
"RTNETLINK answers: File exists"* )
while ! ip link add link "$VM_NET_DEV" name "$VM_NET_TAP" address "$VM_NET_MAC" type macvtap mode bridge; do
info "Waiting for macvtap interface to become available.."
sleep 5
done ;;
"RTNETLINK answers: Invalid argument"* )
error "Cannot create macvtap interface. Please make sure that the network type of the container is 'macvlan' and not 'ipvlan'."
return 1 ;;
"RTNETLINK answers: Operation not permitted"* )
error "No permission to create macvtap interface. Please make sure that your host kernel supports it and that the NET_ADMIN capability is set."
return 1 ;;
*)
[ -n "$msg" ] && echo "$msg" >&2
if (( rc != 0 )); then
error "Cannot create macvtap interface."
return 1
fi ;;
esac
if [[ "$MTU" != "0" ]] && [[ "$MTU" != "1500" ]]; then
if ! ip link set dev "$VM_NET_TAP" mtu "$MTU"; then
warn "Failed to set MTU size.."
fi
fi
while ! ip link set "$VM_NET_TAP" up; do
info "Waiting for MAC address $VM_NET_MAC to become available..."
sleep 2
done
local TAP_NR TAP_PATH MAJOR MINOR
TAP_NR=$(</sys/class/net/"$VM_NET_TAP"/ifindex)
TAP_PATH="/dev/tap${TAP_NR}"
# Create dev file (there is no udev in container: need to be done manually)
IFS=: read -r MAJOR MINOR < <(cat /sys/devices/virtual/net/"$VM_NET_TAP"/tap*/dev)
(( MAJOR < 1)) && error "Cannot find: sys/devices/virtual/net/$VM_NET_TAP" && return 1
[[ ! -e "$TAP_PATH" ]] && [[ -e "/dev0/${TAP_PATH##*/}" ]] && ln -s "/dev0/${TAP_PATH##*/}" "$TAP_PATH"
if [[ ! -e "$TAP_PATH" ]]; then
{ mknod "$TAP_PATH" c "$MAJOR" "$MINOR" ; rc=$?; } || :
(( rc != 0 )) && error "Cannot mknod: $TAP_PATH ($rc)" && return 1
fi
{ exec 30>>"$TAP_PATH"; rc=$?; } 2>/dev/null || :
if (( rc != 0 )); then
error "Cannot create TAP interface ($rc). $ADD_ERR --device-cgroup-rule='c *:* rwm'" && return 1
fi
{ exec 40>>/dev/vhost-net; rc=$?; } 2>/dev/null || :
if (( rc != 0 )); then
error "VHOST can not be found ($rc). $ADD_ERR --device=/dev/vhost-net" && return 1
fi
NET_OPTS="-netdev tap,id=hostnet0,vhost=on,vhostfd=40,fd=30"
return 0
}
configureDNS() {
# dnsmasq configuration:
DNSMASQ_OPTS+=" --dhcp-range=$VM_NET_IP,$VM_NET_IP --dhcp-host=$VM_NET_MAC,,$VM_NET_IP,$VM_NET_HOST,infinite --dhcp-option=option:netmask,255.255.255.0"
# Create lease file for faster resolve
echo "0 $VM_NET_MAC $VM_NET_IP $VM_NET_HOST 01:$VM_NET_MAC" > /var/lib/misc/dnsmasq.leases
chmod 644 /var/lib/misc/dnsmasq.leases
# Set DNS server and gateway
DNSMASQ_OPTS+=" --dhcp-option=option:dns-server,${VM_NET_IP%.*}.1 --dhcp-option=option:router,${VM_NET_IP%.*}.1"
# Add DNS entry for container
DNSMASQ_OPTS+=" --address=/host.lan/${VM_NET_IP%.*}.1"
DNSMASQ_OPTS=$(echo "$DNSMASQ_OPTS" | sed 's/\t/ /g' | tr -s ' ' | sed 's/^ *//')
if [[ "${DEBUG_DNS:-}" == [Yy1]* ]]; then
DNSMASQ_OPTS+=" -d"
$DNSMASQ ${DNSMASQ_OPTS:+ $DNSMASQ_OPTS} &
return 0
fi
if ! $DNSMASQ ${DNSMASQ_OPTS:+ $DNSMASQ_OPTS}; then
error "Failed to start dnsmasq, reason: $?" && return 1
fi
return 0
}
getUserPorts() {
local args=""
local list=$1
local ssh="22"
local rdp="3389"
[ -z "$list" ] && list="$ssh,$rdp" || list+=",$ssh,$rdp"
list="${list//,/ }"
list="${list## }"
list="${list%% }"
for port in $list; do
args+="hostfwd=tcp::$port-$VM_NET_IP:$port,"
done
echo "${args%?}"
return 0
}
getHostPorts() {
local list=$1
local vnc="5900"
local web="8006"
[ -z "$list" ] && list="$web" || list+=",$web"
if [[ "${DISPLAY,,}" == "vnc" ]] || [[ "${DISPLAY,,}" == "web" ]]; then
[ -z "$list" ] && list="$vnc" || list+=",$vnc"
fi
[ -z "$list" ] && echo "" && return 0
if [[ "$list" != *","* ]]; then
echo " ! --dport $list"
else
echo " -m multiport ! --dports $list"
fi
return 0
}
configureUser() {
NET_OPTS="-netdev user,id=hostnet0,host=${VM_NET_IP%.*}.1,net=${VM_NET_IP%.*}.0/24,dhcpstart=$VM_NET_IP,hostname=$VM_NET_HOST"
local forward
forward=$(getUserPorts "$USER_PORTS")
[ -n "$forward" ] && NET_OPTS+=",$forward"
return 0
}
configureNAT() {
local tuntap="TUN device is missing. $ADD_ERR --device /dev/net/tun"
local tables="The 'ip_tables' kernel module is not loaded. Try this command: sudo modprobe ip_tables iptable_nat"
# Create the necessary file structure for /dev/net/tun
if [ ! -c /dev/net/tun ]; then
[ ! -d /dev/net ] && mkdir -m 755 /dev/net
if mknod /dev/net/tun c 10 200; then
chmod 666 /dev/net/tun
fi
fi
if [ ! -c /dev/net/tun ]; then
error "$tuntap" && return 1
fi
# Check port forwarding flag
if [[ $(< /proc/sys/net/ipv4/ip_forward) -eq 0 ]]; then
{ sysctl -w net.ipv4.ip_forward=1 > /dev/null; rc=$?; } || :
if (( rc != 0 )) || [[ $(< /proc/sys/net/ipv4/ip_forward) -eq 0 ]]; then
error "IP forwarding is disabled. $ADD_ERR --sysctl net.ipv4.ip_forward=1" && return 1
fi
fi
# Create a bridge with a static IP for the VM guest
{ ip link add dev dockerbridge type bridge ; rc=$?; } || :
if (( rc != 0 )); then
error "Failed to create bridge. $ADD_ERR --cap-add NET_ADMIN" && return 1
fi
if ! ip address add "${VM_NET_IP%.*}.1/24" broadcast "${VM_NET_IP%.*}.255" dev dockerbridge; then
error "Failed to add IP address pool!" && return 1
fi
while ! ip link set dockerbridge up; do
info "Waiting for IP address to become available..."
sleep 2
done
# QEMU Works with taps, set tap to the bridge created
if ! ip tuntap add dev "$VM_NET_TAP" mode tap; then
error "$tuntap" && return 1
fi
if [[ "$MTU" != "0" ]] && [[ "$MTU" != "1500" ]]; then
if ! ip link set dev "$VM_NET_TAP" mtu "$MTU"; then
warn "Failed to set MTU size.."
fi
fi
GATEWAY_MAC=$(echo "$VM_NET_MAC" | md5sum | sed 's/^\(..\)\(..\)\(..\)\(..\)\(..\).*$/02:\1:\2:\3:\4:\5/')
if ! ip link set dev "$VM_NET_TAP" address "$GATEWAY_MAC"; then
warn "Failed to set gateway MAC address.."
fi
while ! ip link set "$VM_NET_TAP" up promisc on; do
info "Waiting for TAP to become available..."
sleep 2
done
if ! ip link set dev "$VM_NET_TAP" master dockerbridge; then
error "Failed to set IP link!" && return 1
fi
# Add internet connection to the VM
update-alternatives --set iptables /usr/sbin/iptables-legacy > /dev/null
update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy > /dev/null
exclude=$(getHostPorts "$HOST_PORTS")
if ! iptables -t nat -A POSTROUTING -o "$VM_NET_DEV" -j MASQUERADE; then
error "$tables" && return 1
fi
# shellcheck disable=SC2086
if ! iptables -t nat -A PREROUTING -i "$VM_NET_DEV" -d "$IP" -p tcp${exclude} -j DNAT --to "$VM_NET_IP"; then
error "Failed to configure IP tables!" && return 1
fi
if ! iptables -t nat -A PREROUTING -i "$VM_NET_DEV" -d "$IP" -p udp -j DNAT --to "$VM_NET_IP"; then
error "Failed to configure IP tables!" && return 1
fi
if (( KERNEL > 4 )); then
# Hack for guest VMs complaining about "bad udp checksums in 5 packets"
iptables -A POSTROUTING -t mangle -p udp --dport bootpc -j CHECKSUM --checksum-fill > /dev/null 2>&1 || true
fi
NET_OPTS="-netdev tap,id=hostnet0,ifname=$VM_NET_TAP"
if [ -c /dev/vhost-net ]; then
{ exec 40>>/dev/vhost-net; rc=$?; } 2>/dev/null || :
(( rc == 0 )) && NET_OPTS+=",vhost=on,vhostfd=40"
fi
NET_OPTS+=",script=no,downscript=no"
configureDNS || return 1
return 0
}
closeBridge() {
local pid="/var/run/dnsmasq.pid"
[ -s "$pid" ] && pKill "$(<"$pid")"
[[ "${NETWORK,,}" == "user"* ]] && return 0
ip link set "$VM_NET_TAP" down promisc off &> null || true
ip link delete "$VM_NET_TAP" &> null || true
ip link set dockerbridge down &> null || true
ip link delete dockerbridge &> null || true
return 0
}
closeNetwork() {
# Shutdown nginx
nginx -s stop 2> /dev/null
fWait "nginx"
[[ "$NETWORK" == [Nn]* ]] && return 0
exec 30<&- || true
exec 40<&- || true
if [[ "$DHCP" != [Yy1]* ]]; then
closeBridge
return 0
fi
ip link set "$VM_NET_TAP" down || true
ip link delete "$VM_NET_TAP" || true
return 0
}
checkOS() {
local name
local os=""
local if="macvlan"
name=$(uname -a)
[[ "${name,,}" == *"darwin"* ]] && os="Docker Desktop for macOS"
[[ "${name,,}" == *"microsoft"* ]] && os="Docker Desktop for Windows"
if [[ "$DHCP" == [Yy1]* ]]; then
if="macvtap"
[[ "${name,,}" == *"synology"* ]] && os="Synology Container Manager"
fi
if [ -n "$os" ]; then
warn "you are using $os which does not support $if, please revert to bridge networking!"
fi
return 0
}
getInfo() {
if [ -z "$VM_NET_DEV" ]; then
# Give Kubernetes priority over the default interface
[ -d "/sys/class/net/net0" ] && VM_NET_DEV="net0"
[ -d "/sys/class/net/net1" ] && VM_NET_DEV="net1"
[ -d "/sys/class/net/net2" ] && VM_NET_DEV="net2"
[ -d "/sys/class/net/net3" ] && VM_NET_DEV="net3"
# Automaticly detect the default network interface
[ -z "$VM_NET_DEV" ] && VM_NET_DEV=$(awk '$2 == 00000000 { print $1 }' /proc/net/route)
[ -z "$VM_NET_DEV" ] && VM_NET_DEV="eth0"
fi
if [ ! -d "/sys/class/net/$VM_NET_DEV" ]; then
error "Network interface '$VM_NET_DEV' does not exist inside the container!"
error "$ADD_ERR -e \"VM_NET_DEV=NAME\" to specify another interface name." && exit 26
fi
BASE_IP="${VM_NET_IP%.*}."
if [ "${VM_NET_IP/$BASE_IP/}" -lt "3" ]; then
error "Invalid VM_NET_IP, must end in a higher number than .3" && exit 27
fi
if [ -z "$MTU" ]; then
MTU=$(cat "/sys/class/net/$VM_NET_DEV/mtu")
fi
if [ "$MTU" -gt "1500" ]; then
info "MTU size is too large: $MTU, ignoring..." && MTU="0"
fi
if [[ "${ADAPTER,,}" != "virtio-net-pci" ]]; then
if [[ "$MTU" != "0" ]] && [[ "$MTU" != "1500" ]]; then
warn "MTU size is $MTU, but cannot be set for $ADAPTER adapters!" && MTU="0"
fi
fi
if [[ "${BOOT_MODE:-}" == "windows_legacy" ]]; then
if [[ "$MTU" != "0" ]] && [[ "$MTU" != "1500" ]]; then
warn "MTU size is $MTU, but cannot be set for legacy Windows versions!" && MTU="0"
fi
fi
if [ -z "$MAC" ]; then
local file="$STORAGE/$PROCESS.mac"
[ -s "$file" ] && MAC=$(<"$file")
if [ -z "$MAC" ]; then
# Generate MAC address based on Docker container ID in hostname
MAC=$(echo "$HOST" | md5sum | sed 's/^\(..\)\(..\)\(..\)\(..\)\(..\).*$/02:\1:\2:\3:\4:\5/')
echo "${MAC^^}" > "$file"
fi
fi
VM_NET_MAC="${MAC^^}"
VM_NET_MAC="${VM_NET_MAC//-/:}"
if [[ ${#VM_NET_MAC} == 12 ]]; then
m="$VM_NET_MAC"
VM_NET_MAC="${m:0:2}:${m:2:2}:${m:4:2}:${m:6:2}:${m:8:2}:${m:10:2}"
fi
if [[ ${#VM_NET_MAC} != 17 ]]; then
error "Invalid MAC address: '$VM_NET_MAC', should be 12 or 17 digits long!" && exit 28
fi
GATEWAY=$(ip route list dev "$VM_NET_DEV" | awk ' /^default/ {print $3}' | head -n 1)
IP=$(ip address show dev "$VM_NET_DEV" | grep inet | awk '/inet / { print $2 }' | cut -f1 -d/ | head -n 1)
IP6=""
# shellcheck disable=SC2143
if [ -f /proc/net/if_inet6 ] && [ -n "$(ifconfig -a | grep inet6)" ]; then
IP6=$(ip -6 addr show dev "$VM_NET_DEV" scope global up)
[ -n "$IP6" ] && IP6=$(echo "$IP6" | sed -e's/^.*inet6 \([^ ]*\)\/.*$/\1/;t;d' | head -n 1)
fi
return 0
}
# ######################################
# Configure Network
# ######################################
if [[ "$NETWORK" == [Nn]* ]]; then
NET_OPTS=""
return 0
fi
getInfo
html "Initializing network..."
if [[ "$DEBUG" == [Yy1]* ]]; then
mtu=$(cat "/sys/class/net/$VM_NET_DEV/mtu")
line="Host: $HOST IP: $IP Gateway: $GATEWAY Interface: $VM_NET_DEV MAC: $VM_NET_MAC MTU: $mtu"
[[ "$MTU" != "0" ]] && [[ "$MTU" != "$mtu" ]] && line+=" ($MTU)"
info "$line"
if [ -f /etc/resolv.conf ]; then
nameservers=$(grep '^nameserver*' /etc/resolv.conf | head -c -1 | sed 's/nameserver //g;' | sed -z 's/\n/, /g')
[ -n "$nameservers" ] && info "Nameservers: $nameservers"
fi
echo
fi
if [[ -d "/sys/class/net/$VM_NET_TAP" ]]; then
info "Lingering interface will be removed..."
ip link delete "$VM_NET_TAP" || true
fi
if [[ "$DHCP" == [Yy1]* ]]; then
checkOS
if [[ "$IP" == "172."* ]]; then
warn "container IP starts with 172.* which is often a sign that you are not on a macvlan network (required for DHCP)!"
fi
# Configure for macvtap interface
configureDHCP || exit 20
else
if [[ "$IP" != "172."* ]] && [[ "$IP" != "10.8"* ]] && [[ "$IP" != "10.9"* ]]; then
checkOS
fi
if [[ "${NETWORK,,}" != "user"* ]]; then
# Configure for tap interface
if ! configureNAT; then
closeBridge
NETWORK="user"
warn "falling back to user-mode networking! Performance will be bad and port mapping will not work."
fi
fi
if [[ "${NETWORK,,}" == "user"* ]]; then
# Configure for user-mode networking (slirp)
configureUser || exit 24
fi
fi
NET_OPTS+=" -device $ADAPTER,id=net0,netdev=hostnet0,romfile=,mac=$VM_NET_MAC"
[[ "$MTU" != "0" ]] && [[ "$MTU" != "1500" ]] && NET_OPTS+=",host_mtu=$MTU"
html "Initialized network successfully..."
return 0

View file

@ -1,38 +0,0 @@
#!/usr/bin/env bash
set -Eeuo pipefail
escape () {
local s
s=${1//&/\&amp;}
s=${s//</\&lt;}
s=${s//>/\&gt;}
s=${s//'"'/\&quot;}
printf -- %s "$s"
return 0
}
file="$1"
total="$2"
body=$(escape "$3")
info="/run/shm/msg.html"
if [[ "$body" == *"..." ]]; then
body="<p class=\"loading\">${body/.../}</p>"
fi
while true
do
if [ -s "$file" ]; then
bytes=$(du -sb "$file" | cut -f1)
if (( bytes > 1000 )); then
if [ -z "$total" ] || [[ "$total" == "0" ]]; then
size=$(numfmt --to=iec --suffix=B "$bytes" | sed -r 's/([A-Z])/ \1/')
else
size="$(echo "$bytes" "$total" | awk '{printf "%.1f", $1 * 100 / $2}')"
size="$size%"
fi
echo "${body//(\[P\])/($size)}"> "$info"
fi
fi
sleep 1 & wait $!
done

View file

@ -1,175 +0,0 @@
#!/usr/bin/env bash
set -Eeuo pipefail
trap 'error "Status $? while: $BASH_COMMAND (line $LINENO/$BASH_LINENO)"' ERR
[ ! -f "/run/entry.sh" ] && error "Script must run inside Docker container!" && exit 11
[ "$(id -u)" -ne "0" ] && error "Script must be executed with root privileges." && exit 12
echo " Starting $APP for Docker v$(</run/version)..."
echo " For support visit $SUPPORT"
# Docker environment variables
: "${BOOT:=""}" # URL of the ISO file
: "${DEBUG:="N"}" # Disable debugging
: "${MACHINE:="virt"}" # Machine selection
: "${ALLOCATE:=""}" # Preallocate diskspace
: "${ARGUMENTS:=""}" # Extra QEMU parameters
: "${CPU_CORES:="2"}" # Amount of CPU cores
: "${RAM_SIZE:="2G"}" # Maximum RAM amount
: "${RAM_CHECK:="Y"}" # Check available RAM
: "${DISK_SIZE:="16G"}" # Initial data disk size
: "${BOOT_MODE:=""}" # Boot system with UEFI
: "${BOOT_INDEX:="9"}" # Boot index of CD drive
: "${STORAGE:="/storage"}" # Storage folder location
# Helper variables
PROCESS="${APP,,}"
PROCESS="${PROCESS// /-}"
INFO="/run/shm/msg.html"
PAGE="/run/shm/index.html"
TEMPLATE="/var/www/index.html"
FOOTER1="$APP for Docker v$(</run/version)"
FOOTER2="<a href='$SUPPORT'>$SUPPORT</a>"
CPU=$(cpu)
SYS=$(uname -r)
HOST=$(hostname -s)
KERNEL=$(echo "$SYS" | cut -b 1)
MINOR=$(echo "$SYS" | cut -d '.' -f2)
ARCH=$(dpkg --print-architecture)
CORES=$(grep -c '^processor' /proc/cpuinfo)
if ! grep -qi "socket(s)" <<< "$(lscpu)"; then
SOCKETS=1
else
SOCKETS=$(lscpu | grep -m 1 -i 'socket(s)' | awk '{print $(2)}')
fi
[ -n "${CPU_CORES//[0-9 ]}" ] && error "Invalid amount of CPU_CORES: $CPU_CORES" && exit 15
# Check system
if [ ! -d "/dev/shm" ]; then
error "Directory /dev/shm not found!" && exit 14
else
[ ! -d "/run/shm" ] && ln -s /dev/shm /run/shm
fi
# Check folder
if [[ "${COMMIT:-}" == [Yy1]* ]]; then
STORAGE="/local"
mkdir -p "$STORAGE"
fi
if [ ! -d "$STORAGE" ]; then
error "Storage folder ($STORAGE) not found!" && exit 13
fi
# Read memory
RAM_SPARE=500000000
RAM_AVAIL=$(free -b | grep -m 1 Mem: | awk '{print $7}')
RAM_TOTAL=$(free -b | grep -m 1 Mem: | awk '{print $2}')
RAM_SIZE="${RAM_SIZE// /}"
[ -z "$RAM_SIZE" ] && error "RAM_SIZE not specified!" && exit 16
if [ -z "${RAM_SIZE//[0-9. ]}" ]; then
[ "${RAM_SIZE%%.*}" -lt "130" ] && RAM_SIZE="${RAM_SIZE}G" || RAM_SIZE="${RAM_SIZE}M"
fi
RAM_SIZE=$(echo "${RAM_SIZE^^}" | sed 's/MB/M/g;s/GB/G/g;s/TB/T/g')
! numfmt --from=iec "$RAM_SIZE" &>/dev/null && error "Invalid RAM_SIZE: $RAM_SIZE" && exit 16
RAM_WANTED=$(numfmt --from=iec "$RAM_SIZE")
[ "$RAM_WANTED" -lt "136314880 " ] && error "RAM_SIZE is too low: $RAM_SIZE" && exit 16
# Print system info
SYS="${SYS/-generic/}"
FS=$(stat -f -c %T "$STORAGE")
FS="${FS/UNKNOWN //}"
FS="${FS/ext2\/ext3/ext4}"
FS=$(echo "$FS" | sed 's/[)(]//g')
SPACE=$(df --output=avail -B 1 "$STORAGE" | tail -n 1)
SPACE_GB=$(formatBytes "$SPACE" "down")
AVAIL_MEM=$(formatBytes "$RAM_AVAIL" "down")
TOTAL_MEM=$(formatBytes "$RAM_TOTAL" "up")
echo " CPU: ${CPU} | RAM: ${AVAIL_MEM/ GB/}/$TOTAL_MEM | DISK: $SPACE_GB (${FS}) | KERNEL: ${SYS}..."
echo
# Check compatibilty
if [[ "${FS,,}" == "ecryptfs" ]] || [[ "${FS,,}" == "tmpfs" ]]; then
DISK_IO="threads"
DISK_CACHE="writeback"
fi
if [[ "${BOOT_MODE:-}" == "windows"* ]]; then
if [[ "${FS,,}" == "btrfs" ]]; then
warn "you are using the BTRFS filesystem for /storage, this might introduce issues with Windows Setup!"
fi
fi
# Check available memory
if [[ "$RAM_CHECK" != [Nn]* ]] && (( (RAM_WANTED + RAM_SPARE) > RAM_AVAIL )); then
AVAIL_MEM=$(formatBytes "$RAM_AVAIL")
msg="Your configured RAM_SIZE of ${RAM_SIZE/G/ GB} is too high for the $AVAIL_MEM of memory available, please set a lower value."
[[ "${FS,,}" != "zfs" ]] && error "$msg" && exit 17
info "$msg"
fi
addPackage() {
local pkg=$1
local desc=$2
if apt-mark showinstall | grep -qx "$pkg"; then
return 0
fi
MSG="Installing $desc..."
info "$MSG" && html "$MSG"
DEBIAN_FRONTEND=noninteractive apt-get -qq update
DEBIAN_FRONTEND=noninteractive apt-get -qq --no-install-recommends -y install "$pkg" > /dev/null
return 0
}
user="admin"
[ -n "${USER:-}" ] && user="${USER:-}"
if [ -n "${PASS:-}" ]; then
sed -i "s/auth_basic off/auth_basic \"NoVNC\"/g" /etc/nginx/sites-enabled/web.conf
else
sed -i "s/auth_basic \"NoVNC\"/auth_basic off/g" /etc/nginx/sites-enabled/web.conf
fi
# Set password
echo "$user:{PLAIN}${PASS:-}" > /etc/nginx/.htpasswd
# shellcheck disable=SC2143
if [ -f /proc/net/if_inet6 ] && [ -n "$(ifconfig -a | grep inet6)" ]; then
sed -i "s/listen 8006 default_server;/listen [::]:8006 default_server ipv6only=off;/g" /etc/nginx/sites-enabled/web.conf
else
sed -i "s/listen [::]:8006 default_server ipv6only=off;/listen 8006 default_server;/g" /etc/nginx/sites-enabled/web.conf
fi
# Start webserver
cp -r /var/www/* /run/shm
html "Starting $APP for Docker..."
nginx -e stderr
return 0

View file

@ -1,171 +0,0 @@
#!/usr/bin/env bash
set -Eeuo pipefail
# Helper functions
info () { printf "%b%s%b" "\E[1;34m \E[1;36m" "${1:-}" "\E[0m\n"; }
error () { printf "%b%s%b" "\E[1;31m " "ERROR: ${1:-}" "\E[0m\n" >&2; }
warn () { printf "%b%s%b" "\E[1;31m " "Warning: ${1:-}" "\E[0m\n" >&2; }
formatBytes() {
local result
result=$(numfmt --to=iec --suffix=B "$1" | sed -r 's/([A-Z])/ \1/' | sed 's/ B/ bytes/g;')
local unit="${result//[0-9. ]}"
result="${result//[a-zA-Z ]/}"
if [[ "${2:-}" == "up" ]]; then
if [[ "$result" == *"."* ]]; then
result="${result%%.*}"
result=$((result+1))
fi
else
if [[ "${2:-}" == "down" ]]; then
result="${result%%.*}"
fi
fi
echo "$result $unit"
return 0
}
isAlive() {
local pid="$1"
if kill -0 "$pid" 2>/dev/null; then
return 0
fi
return 1
}
pKill() {
local pid="$1"
{ kill -15 "$pid" || true; } 2>/dev/null
while isAlive "$pid"; do
sleep 0.2
done
return 0
}
fWait() {
local name="$1"
while pgrep -f -l "$name" >/dev/null; do
sleep 0.2
done
return 0
}
fKill() {
local name="$1"
{ pkill -f "$name" || true; } 2>/dev/null
fWait "$name"
return 0
}
escape () {
local s
s=${1//&/\&amp;}
s=${s//</\&lt;}
s=${s//>/\&gt;}
s=${s//'"'/\&quot;}
printf -- %s "$s"
return 0
}
html() {
local title
local body
local script
local footer
title=$(escape "$APP")
title="<title>$title</title>"
footer=$(escape "$FOOTER1")
body=$(escape "$1")
if [[ "$body" == *"..." ]]; then
body="<p class=\"loading\">${body/.../}</p>"
fi
[ -n "${2:-}" ] && script="$2" || script=""
local HTML
HTML=$(<"$TEMPLATE")
HTML="${HTML/\[1\]/$title}"
HTML="${HTML/\[2\]/$script}"
HTML="${HTML/\[3\]/$body}"
HTML="${HTML/\[4\]/$footer}"
HTML="${HTML/\[5\]/$FOOTER2}"
echo "$HTML" > "$PAGE"
echo "$body" > "$INFO"
return 0
}
cpu() {
local ret
local cpu=""
ret=$(lscpu)
if grep -qi "model name" <<< "$ret"; then
cpu=$(echo "$ret" | grep -m 1 -i 'model name' | cut -f 2 -d ":" | awk '{$1=$1}1' | sed 's# @.*##g' | sed s/"(R)"//g | sed 's/[^[:alnum:] ]\+/ /g' | sed 's/ */ /g')
fi
if [ -z "${cpu// /}" ] && grep -qi "model:" <<< "$ret"; then
cpu=$(echo "$ret" | grep -m 1 -i 'model:' | cut -f 2 -d ":" | awk '{$1=$1}1' | sed 's# @.*##g' | sed s/"(R)"//g | sed 's/[^[:alnum:] ]\+/ /g' | sed 's/ */ /g')
fi
cpu="${cpu// CPU/}"
cpu="${cpu// 4 Core/}"
cpu="${cpu// 6 Core/}"
cpu="${cpu// 8 Core/}"
cpu="${cpu// 10 Core/}"
cpu="${cpu// 12 Core/}"
cpu="${cpu// 16 Core/}"
cpu="${cpu// 32 Core/}"
cpu="${cpu// 64 Core/}"
cpu="${cpu//7th Gen /}"
cpu="${cpu//8th Gen /}"
cpu="${cpu//9th Gen /}"
cpu="${cpu//10th Gen /}"
cpu="${cpu//11th Gen /}"
cpu="${cpu//12th Gen /}"
cpu="${cpu//13th Gen /}"
cpu="${cpu//14th Gen /}"
cpu="${cpu//15th Gen /}"
cpu="${cpu// Processor/}"
cpu="${cpu// Quad core/}"
cpu="${cpu// Dual core/}"
cpu="${cpu// Octa core/}"
cpu="${cpu// Core TM/ Core}"
cpu="${cpu// with Radeon Graphics/}"
cpu="${cpu// with Radeon Vega Graphics/}"
[ -z "${cpu// /}" ] && cpu="Unknown"
echo "$cpu"
return 0
}
hasDisk() {
[ -b "/disk" ] && return 0
[ -b "/disk1" ] && return 0
[ -b "/dev/disk1" ] && return 0
[ -b "${DEVICE:-}" ] && return 0
[ -z "${DISK_NAME:-}" ] && DISK_NAME="data"
[ -s "$STORAGE/$DISK_NAME.img" ] && return 0
[ -s "$STORAGE/$DISK_NAME.qcow2" ] && return 0
return 1
}
return 0