From ad2458ea425894bb4ed45678ce74b2564d02f088 Mon Sep 17 00:00:00 2001 From: Kroese Date: Thu, 20 Mar 2025 02:49:36 +0100 Subject: [PATCH] build: Refactor shared code (#220) --- Dockerfile | 16 +- src/config.sh | 2 +- src/define.sh | 224 ---------------- src/disk.sh | 683 ------------------------------------------------ src/entry.sh | 1 + src/install.sh | 344 ------------------------ src/network.sh | 508 ----------------------------------- src/progress.sh | 38 --- src/reset.sh | 175 ------------- src/utils.sh | 171 ------------ 10 files changed, 10 insertions(+), 2152 deletions(-) delete mode 100644 src/define.sh delete mode 100644 src/disk.sh delete mode 100644 src/install.sh delete mode 100644 src/network.sh delete mode 100644 src/progress.sh delete mode 100644 src/reset.sh delete mode 100644 src/utils.sh diff --git a/Dockerfile b/Dockerfile index 8da4e26..938badc 100644 --- a/Dockerfile +++ b/Dockerfile @@ -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 diff --git a/src/config.sh b/src/config.sh index 3f87fdc..368292b 100644 --- a/src/config.sh +++ b/src/config.sh @@ -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 diff --git a/src/define.sh b/src/define.sh deleted file mode 100644 index dd84043..0000000 --- a/src/define.sh +++ /dev/null @@ -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 diff --git a/src/disk.sh b/src/disk.sh deleted file mode 100644 index db00b2e..0000000 --- a/src/disk.sh +++ /dev/null @@ -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 diff --git a/src/entry.sh b/src/entry.sh index 69a83c4..27d7066 100755 --- a/src/entry.sh +++ b/src/entry.sh @@ -2,6 +2,7 @@ set -Eeuo pipefail : "${APP:="QEMU"}" +: "${MACHINE:="virt"}" : "${SUPPORT:="https://github.com/qemus/qemu-arm"}" cd /run diff --git a/src/install.sh b/src/install.sh deleted file mode 100644 index 44a771b..0000000 --- a/src/install.sh +++ /dev/null @@ -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 diff --git a/src/network.sh b/src/network.sh deleted file mode 100644 index 7d41248..0000000 --- a/src/network.sh +++ /dev/null @@ -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=$(>"$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 diff --git a/src/progress.sh b/src/progress.sh deleted file mode 100644 index 9c7549f..0000000 --- a/src/progress.sh +++ /dev/null @@ -1,38 +0,0 @@ -#!/usr/bin/env bash -set -Eeuo pipefail - -escape () { - local s - s=${1//&/\&} - s=${s///\>} - s=${s//'"'/\"} - printf -- %s "$s" - return 0 -} - -file="$1" -total="$2" -body=$(escape "$3") -info="/run/shm/msg.html" - -if [[ "$body" == *"..." ]]; then - body="

${body/.../}

" -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 diff --git a/src/reset.sh b/src/reset.sh deleted file mode 100644 index 5ced84a..0000000 --- a/src/reset.sh +++ /dev/null @@ -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$(/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 diff --git a/src/utils.sh b/src/utils.sh deleted file mode 100644 index ed53adc..0000000 --- a/src/utils.sh +++ /dev/null @@ -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//&/\&} - s=${s///\>} - s=${s//'"'/\"} - printf -- %s "$s" - return 0 -} - -html() { - local title - local body - local script - local footer - - title=$(escape "$APP") - title="$title" - footer=$(escape "$FOOTER1") - - body=$(escape "$1") - if [[ "$body" == *"..." ]]; then - body="

${body/.../}

" - 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