Compare commits

..

No commits in common. "master" and "v7.31" have entirely different histories.

16 changed files with 391 additions and 381 deletions

View File

@ -1,6 +0,0 @@
{
"name": "dsm",
"service": "dsm",
"forwardPorts": [5000],
"dockerComposeFile": "compose.yml"
}

View File

@ -21,7 +21,6 @@ body:
attributes:
label: Docker compose
description: The compose file (or otherwise the `docker run` command used).
render: yaml
validations:
required: true
- type: textarea
@ -29,7 +28,6 @@ body:
attributes:
label: Docker log
description: The logfile of the container (as shown by `docker logs dsm`).
render: shell
validations:
required: true
- type: textarea

View File

@ -23,7 +23,6 @@ body:
attributes:
label: Docker compose
description: The compose file (or otherwise the `docker run` command used).
render: yaml
validations:
required: true
- type: textarea
@ -31,7 +30,6 @@ body:
attributes:
label: Docker log
description: The logfile of the container (as shown by `docker logs dsm`).
render: shell
validations:
required: true
- type: textarea

View File

@ -20,5 +20,5 @@ jobs:
uses: hadolint/hadolint-action@v3.1.0
with:
dockerfile: Dockerfile
ignore: DL3008,DL3003,DL3006,DL3013
ignore: DL3008,DL3003,DL3006
failure-threshold: warning

View File

@ -15,21 +15,19 @@ ARG DEBCONF_NOWARNINGS="yes"
ARG DEBIAN_FRONTEND="noninteractive"
ARG DEBCONF_NONINTERACTIVE_SEEN="true"
RUN set -eu && \
RUN set -eu && extra="" && \
if [ "$TARGETPLATFORM" != "linux/amd64" ]; then extra="qemu-user"; fi && \
apt-get update && \
apt-get --no-install-recommends -y install \
jq \
tini \
curl \
cpio \
wget \
fdisk \
unzip \
nginx \
procps \
python3 \
python3-pip \
python3-msgpack \
python3-pysodium \
xz-utils \
iptables \
iproute2 \
@ -42,9 +40,9 @@ RUN set -eu && \
iputils-ping \
ca-certificates \
netcat-openbsd \
qemu-system-x86 && \
qemu-system-x86 \
"$extra" && \
apt-get clean && \
pip3 install --no-cache-dir --break-system-packages --root-user-action=ignore dissect.cstruct && \
mkdir -p /etc/qemu && \
echo "allow br0" > /etc/qemu/bridge.conf && \
unlink /etc/nginx/sites-enabled/default && \
@ -56,14 +54,13 @@ COPY --chmod=755 ./src /run/
COPY --chmod=755 ./web /var/www/
COPY --chmod=755 --from=builder /qemu-host.bin /run/host.bin
COPY --chmod=744 ./web/conf/nginx.conf /etc/nginx/sites-enabled/web.conf
ADD --chmod=775 https://raw.githubusercontent.com/sud0woodo/patology/refs/heads/main/patology.py /run/extract.py
VOLUME /storage
EXPOSE 22 139 445 5000
ENV RAM_SIZE="2G"
ENV CPU_CORES="2"
ENV RAM_SIZE="1G"
ENV DISK_SIZE="16G"
ENV CPU_CORES="1"
HEALTHCHECK --interval=60s --start-period=45s --retries=2 CMD /run/check.sh

View File

@ -22,7 +22,7 @@ Virtual DSM in a Docker container.
## Usage 🐳
##### Via Docker Compose:
Via Docker Compose:
```yaml
services:
@ -44,21 +44,27 @@ services:
stop_grace_period: 2m
```
##### Via Docker CLI:
Via Docker CLI:
```bash
docker run -it --rm --name dsm -p 5000:5000 --device=/dev/kvm --device=/dev/net/tun --cap-add NET_ADMIN -v "${PWD:-.}/dsm:/storage" --stop-timeout 120 vdsm/virtual-dsm
docker run -it --rm --name dsm -p 5000:5000 --device=/dev/kvm --device=/dev/net/tun --cap-add NET_ADMIN -v ${PWD:-.}/dsm:/storage --stop-timeout 120 vdsm/virtual-dsm
```
##### Via Kubernetes:
Via Kubernetes:
```shell
kubectl apply -f https://raw.githubusercontent.com/vdsm/virtual-dsm/refs/heads/master/kubernetes.yml
```
##### Via Github Codespaces:
## Compatibility ⚙️
[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/vdsm/virtual-dsm)
| **Product** | **Platform** | |
|---|---|---|
| Docker Engine | Linux| ✅ |
| Docker Desktop | Linux | ❌ |
| Docker Desktop | macOS | ❌ |
| Docker Desktop | Windows 11 | ✅ |
| Docker Desktop | Windows 10 | ❌ |
## FAQ 💬
@ -123,19 +129,25 @@ kubectl apply -f https://raw.githubusercontent.com/vdsm/virtual-dsm/refs/heads/m
### How do I pass-through a disk?
It is possible to pass-through disk devices or partitions directly by adding them to your compose file in this way:
It is possible to pass-through a disk device directly, which can be useful when your host is a virtual machine, as it removes an extra layer and allows for easier management. For use with physical disks this method provides little advantage and is not recommended.
You can add the virtual device to your compose file like this:
```yaml
devices:
- /dev/sdb:/disk1
- /dev/sdc1:/disk2
- /dev/disk/by-uuid/12345-12345-12345-12345-12345:/disk2
```
Make sure it is totally empty (without any filesystem), otherwise DSM may not format it as a volume.
The device needs to be totally empty (without any partition table) otherwise DSM does not always format it into a volume.
Make sure to bind the disk via its UUID (obtainable via `lsblk -o name,uuid`) instead of its name (`/dev/sdc`), to prevent ever binding the wrong disk when the drive letters happen to change.
> [!CAUTION]
> Do NOT use this feature with the goal of sharing files from the host, they might all get lost without warning when DSM creates the volume.
### How do I change the amount of CPU or RAM?
By default, the container will be allowed to use a maximum of 2 CPU cores and 2 GB of RAM.
By default, the container will be allowed to use a maximum of 1 CPU core and 1 GB of RAM.
If you want to adjust this, you can specify the desired amount using the following environment variables:
@ -147,16 +159,9 @@ kubectl apply -f https://raw.githubusercontent.com/vdsm/virtual-dsm/refs/heads/m
### How do I verify if my system supports KVM?
First check if your software is compatible using this chart:
| **Product** | **Linux** | **Win11** | **Win10** | **macOS** |
|---|---|---|---|---|
| Docker CLI | ✅ | ✅ | ❌ | ❌ |
| Docker Desktop | ❌ | ✅ | ❌ | ❌ |
| Podman CLI | ✅ | ✅ | ❌ | ❌ |
| Podman Desktop | ✅ | ✅ | ❌ | ❌ |
After that you can run the following commands in Linux to check your system:
Only Linux and Windows 11 support KVM virtualization, macOS and Windows 10 do not unfortunately.
You can run the following commands in Linux to check your system:
```bash
sudo apt install cpu-checker
@ -171,7 +176,11 @@ kubectl apply -f https://raw.githubusercontent.com/vdsm/virtual-dsm/refs/heads/m
- you are not using a cloud provider, as most of them do not allow nested virtualization for their VPS's.
If you did not receive any error from `kvm-ok` but the container still complains about a missing KVM device, it could help to add `privileged: true` to your compose file (or `sudo` to your `docker` command) to rule out any permission issue.
If you do not receive any error from `kvm-ok` but the container still complains about KVM, please check whether:
- you are not using "Docker Desktop for Linux" as it does not support KVM, instead make use of Docker Engine directly.
- it could help to add `privileged: true` to your compose file (or `sudo` to your `docker run` command), to rule out any permission issue.
### How do I assign an individual IP address to the container?
@ -250,14 +259,14 @@ kubectl apply -f https://raw.githubusercontent.com/vdsm/virtual-dsm/refs/heads/m
With this method, it is even possible to switch back and forth between versions while keeping your file data intact.
Alternatively, you can also skip the download and use a local file instead, by binding it in your compose file in this way:
If you don't have internet access, it's also possible to skip the download by setting `URL` to:
```yaml
volumes:
- ./DSM_VirtualDSM_42218.pat:/boot.pat
environment:
URL: "DSM_VirtualDSM_42218.pat"
```
Replace the example path `./DSM_VirtualDSM_42218.pat` with the filename of your desired `.pat` file. The value of `URL` will be ignored in this case.
after placing a copy of [DSM_VirtualDSM_42218.pat](https://global.synologydownload.com/download/DSM/release/7.0.1/42218/DSM_VirtualDSM_42218.pat) in the root of your `/storage` folder.
### What are the differences compared to the standard DSM?

View File

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

View File

@ -320,7 +320,7 @@ convertDisk() {
msg="Conversion of $DISK_DESC"
html "$msg completed..."
info "$msg to $DST_FMT completed successfully!"
info "$msg to $DST_FMT completed succesfully!"
return 0
}
@ -368,8 +368,6 @@ createDevice () {
local DISK_FMT=$5
local DISK_IO=$6
local DISK_CACHE=$7
local DISK_SERIAL=$8
local DISK_SECTORS=$9
local DISK_ID="data$DISK_INDEX"
local index=""
@ -383,29 +381,29 @@ createDevice () {
;;
"usb" )
result+=",if=none \
-device usb-storage,drive=${DISK_ID}${index}${DISK_SERIAL}${DISK_SECTORS}"
-device usb-storage,drive=${DISK_ID}${index}"
echo "$result"
;;
"nvme" )
result+=",if=none \
-device nvme,drive=${DISK_ID}${index},serial=deadbeaf${DISK_INDEX}${DISK_SERIAL}${DISK_SECTORS}"
-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}${DISK_SERIAL}${DISK_SECTORS}"
-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}${DISK_SERIAL}${DISK_SECTORS}"
-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}${DISK_SERIAL}${DISK_SECTORS}"
-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
@ -484,7 +482,7 @@ addDisk () {
fi
DISK_OPTS+=$(createDevice "$DISK_FILE" "$DISK_TYPE" "$DISK_INDEX" "$DISK_ADDRESS" "$DISK_FMT" "$DISK_IO" "$DISK_CACHE" "" "")
DISK_OPTS+=$(createDevice "$DISK_FILE" "$DISK_TYPE" "$DISK_INDEX" "$DISK_ADDRESS" "$DISK_FMT" "$DISK_IO" "$DISK_CACHE")
return 0
}
@ -499,26 +497,7 @@ addDevice () {
[ -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
local sectors=""
local result logical physical
result=$(fdisk -l "$DISK_DEV" | grep -m 1 -o "(logical/physical): .*" | cut -c 21-)
logical="${result%% *}"
physical=$(echo "$result" | grep -m 1 -o "/ .*" | cut -c 3-)
physical="${physical%% *}"
if [ -n "$physical" ]; then
if [[ "$physical" == "512" ]] || [[ "$physical" == "4096" ]]; then
if [[ "$physical" == "4096" ]]; then
sectors=",logical_block_size=$logical,physical_block_size=$physical"
fi
else
warn "Unknown physical sector size: $physical for $DISK_DEV"
fi
else
warn "Failed to determine the sector size for $DISK_DEV"
fi
DISK_OPTS+=$(createDevice "$DISK_DEV" "$DISK_TYPE" "$DISK_INDEX" "$DISK_ADDRESS" "raw" "$DISK_IO" "$DISK_CACHE" "" "$sectors")
DISK_OPTS+=$(createDevice "$DISK_DEV" "$DISK_TYPE" "$DISK_INDEX" "$DISK_ADDRESS" "raw" "$DISK_IO" "$DISK_CACHE")
return 0
}
@ -550,8 +529,8 @@ else
DISK_ALLOC="preallocation=falloc"
fi
DISK_OPTS+=$(createDevice "$BOOT" "$DISK_TYPE" "1" "0xa" "raw" "$DISK_IO" "$DISK_CACHE" "" "")
DISK_OPTS+=$(createDevice "$SYSTEM" "$DISK_TYPE" "2" "0xb" "raw" "$DISK_IO" "$DISK_CACHE" "" "")
DISK_OPTS+=$(createDevice "$BOOT" "$DISK_TYPE" "1" "0xa" "raw" "$DISK_IO" "$DISK_CACHE")
DISK_OPTS+=$(createDevice "$SYSTEM" "$DISK_TYPE" "2" "0xb" "raw" "$DISK_IO" "$DISK_CACHE")
DISK1_FILE="$STORAGE/${DISK_NAME}"
if [[ ! -f "$DISK1_FILE.img" ]] && [[ -f "$STORAGE/data${DISK_SIZE}.img" ]]; then

View File

@ -8,9 +8,7 @@ set -Eeuo pipefail
: "${DISPLAY:="none"}" # Display type
: "${RENDERNODE:="/dev/dri/renderD128"}" # Render node
CPU_VENDOR=$(lscpu | awk '/Vendor ID/{print $3}')
if [[ "$GPU" != [Yy1]* ]] || [[ "$CPU_VENDOR" != "GenuineIntel" ]] || [[ "$ARCH" != "amd64" ]]; then
if [[ "$GPU" != [Yy1]* ]] || [[ "$ARCH" != "amd64" ]]; then
[[ "${DISPLAY,,}" == "none" ]] && VGA="none"
DISPLAY_OPTS="-display $DISPLAY -vga $VGA"

View File

@ -6,7 +6,6 @@ set -Eeuo pipefail
cd /run
. utils.sh # Load functions
. reset.sh # Initialize system
. install.sh # Run installation
. disk.sh # Initialize disks

View File

@ -5,38 +5,25 @@ set -Eeuo pipefail
if [ -f "$STORAGE/dsm.ver" ]; then
BASE=$(<"$STORAGE/dsm.ver")
BASE="${BASE//[![:print:]]/}"
[ -z "$BASE" ] && BASE="DSM_VirtualDSM_69057"
else
# Fallback for old installs
BASE="DSM_VirtualDSM_42962"
fi
FN="boot.pat"
DIR=$(find / -maxdepth 1 -type d -iname "$FN" -print -quit)
[ ! -d "$DIR" ] && DIR=$(find "$STORAGE" -maxdepth 1 -type d -iname "$FN" -print -quit)
if [ -d "$DIR" ]; then
BASE="DSM_VirtualDSM" && URL="file://$DIR"
if [[ ! -s "$STORAGE/$BASE.boot.img" ]] || [[ ! -s "$STORAGE/$BASE.system.img" ]]; then
error "The bind $DIR maps to a file that does not exist!" && exit 65
fi
fi
FILE=$(find / -maxdepth 1 -type f -iname "$FN" -print -quit)
[ ! -s "$FILE" ] && FILE=$(find "$STORAGE" -maxdepth 1 -type f -iname "$FN" -print -quit)
[ -s "$FILE" ] && BASE="DSM_VirtualDSM" && URL="file://$FILE"
if [ -n "$URL" ] && [ ! -s "$FILE" ] && [ ! -d "$DIR" ]; then
if [ -n "$URL" ]; then
BASE=$(basename "$URL" .pat)
if [ ! -s "$STORAGE/$BASE.system.img" ]; then
BASE=$(basename "${URL%%\?*}" .pat)
: "${BASE//+/ }"; printf -v BASE '%b' "${_//%/\\x}"
BASE=$(echo "$BASE" | sed -e 's/[^A-Za-z0-9._-]/_/g')
fi
if [[ "${URL,,}" != "http"* ]] && [[ "${URL,,}" != "file:"* ]] ; then
[ ! -s "$STORAGE/$BASE.pat" ] && error "Invalid URL: $URL" && exit 65
URL="file://$STORAGE/$BASE.pat"
if [[ "${URL,,}" != "http"* ]]; then
if [ -s "$STORAGE/$BASE.pat" ]; then
URL="file://$STORAGE/$BASE.pat"
else
error "File $STORAGE/$BASE.pat does not exist!" && exit 65
fi
fi
fi
@ -59,15 +46,11 @@ if [ -z "$DL" ]; then
[[ "${COUNTRY^^}" == "CN" ]] && DL="$DL_CHINA" || DL="$DL_GLOBAL"
fi
if [ -z "$URL" ]; then
URL="$DL/release/7.2.2/72806/DSM_VirtualDSM_72806.pat"
fi
[ -z "$URL" ] && URL="$DL/release/7.2.2/72806/DSM_VirtualDSM_72806.pat"
if [ ! -s "$FILE" ]; then
BASE=$(basename "${URL%%\?*}" .pat)
: "${BASE//+/ }"; printf -v BASE '%b' "${_//%/\\x}"
BASE=$(echo "$BASE" | sed -e 's/[^A-Za-z0-9._-]/_/g')
fi
BASE=$(basename "${URL%%\?*}" .pat)
: "${BASE//+/ }"; printf -v BASE '%b' "${_//%/\\x}"
BASE=$(echo "$BASE" | sed -e 's/[^A-Za-z0-9._-]/_/g')
if [[ "$URL" != "file://$STORAGE/$BASE.pat" ]]; then
rm -f "$STORAGE/$BASE.pat"
@ -128,16 +111,128 @@ else
PROGRESS="--progress=dot:giga"
fi
if [[ "$URL" == "file://"* ]]; then
MSG="Copying DSM"
ERR="Failed to copy ${URL:7}"
info "Install: Copying installation image..."
else
MSG="Downloading DSM"
ERR="Failed to download $URL"
info "Install: Downloading $BASE.pat..."
# Download the required files from the Synology website
ROOT="Y"
RD="$TMP/rd.gz"
RDC="$STORAGE/dsm.rd"
if [ ! -s "$RDC" ] && [[ "$URL" == "file://"* ]] && [[ "${URL,,}" == *"_42218.pat" ]]; then
rm -f "$RD"
rm -f "$RDC"
tar --extract --file="${URL:7}" --directory="$(dirname "$RD")"/. "$(basename "$RD")"
cp "$RD" "$RDC"
fi
if [ ! -s "$RDC" ]; then
rm -f "$RD"
rm -f "$RDC"
MSG="Downloading installer"
info "Install: $MSG..." && html "$MSG..."
SIZE=5394188
POS="65627648-71021835"
VERIFY="b4215a4b213ff5154db0488f92c87864"
LOC="$DL/release/7.0.1/42218/DSM_VirtualDSM_42218.pat"
[[ "${URL,,}" == *"_42218.pat" ]] && LOC="$URL"
/run/progress.sh "$RD" "$SIZE" "$MSG ([P])..." &
{ curl -r "$POS" -sfk --connect-timeout 10 -S -o "$RD" "$LOC"; rc=$?; } || :
fKill "progress.sh"
ERR="Failed to download $LOC"
(( rc == 3 )) && error "$ERR , cannot write file (disk full?)" && exit 60
(( rc == 4 )) && error "$ERR , network failure!" && exit 60
(( rc == 8 )) && error "$ERR , server issued an error response!" && exit 60
if (( rc != 0 )); then
if (( rc != 22 )) && (( rc != 56 )); then
error "$ERR , reason: $rc" && exit 60
fi
SUM="skip"
else
SUM=$(md5sum "$RD" | cut -f 1 -d " ")
fi
if [ "$SUM" != "$VERIFY" ]; then
PAT="/install.pat"
SIZE=379637760
rm -f "$RD"
rm -f "$PAT"
html "$MSG..."
/run/progress.sh "$PAT" "$SIZE" "$MSG ([P])..." &
{ wget "$LOC" -O "$PAT" -q --no-check-certificate --timeout=10 --no-http-keep-alive --show-progress "$PROGRESS"; rc=$?; } || :
fKill "progress.sh"
ERR="Failed to download $LOC"
(( rc == 3 )) && error "$ERR , cannot write file (disk full?)" && exit 60
(( rc == 4 )) && error "$ERR , network failure!" && exit 60
(( rc == 8 )) && error "$ERR , server issued an error response!" && exit 60
(( rc != 0 )) && error "$ERR , reason: $rc" && exit 60
tar --extract --file="$PAT" --directory="$(dirname "$RD")"/. "$(basename "$RD")"
rm "$PAT"
fi
cp "$RD" "$RDC"
fi
if [ -f "$RDC" ]; then
{ xz -dc <"$RDC" >"$TMP/rd" 2>/dev/null; rc=$?; } || :
(( rc != 1 )) && error "Failed to unxz $RDC on $FS, reason $rc" && exit 91
{ (cd "$TMP" && cpio -idm <"$TMP/rd" 2>/dev/null); rc=$?; } || :
if (( rc != 0 )); then
ROOT="N"
{ (cd "$TMP" && fakeroot cpio -idmu <"$TMP/rd" 2>/dev/null); rc=$?; } || :
(( rc != 0 )) && error "Failed to extract $RDC on $FS, reason $rc" && exit 92
fi
rm -rf /run/extract && mkdir -p /run/extract
for file in $TMP/usr/lib/libcurl.so.4 \
$TMP/usr/lib/libmbedcrypto.so.5 \
$TMP/usr/lib/libmbedtls.so.13 \
$TMP/usr/lib/libmbedx509.so.1 \
$TMP/usr/lib/libmsgpackc.so.2 \
$TMP/usr/lib/libsodium.so \
$TMP/usr/lib/libsynocodesign-ng-virtual-junior-wins.so.7 \
$TMP/usr/syno/bin/scemd; do
cp "$file" /run/extract/
done
if [ "$ARCH" != "amd64" ]; then
mkdir -p /lib64/
cp "$TMP/usr/lib/libc.so.6" /lib64/
cp "$TMP/usr/lib/libpthread.so.0" /lib64/
cp "$TMP/usr/lib/ld-linux-x86-64.so.2" /lib64/
fi
mv /run/extract/scemd /run/extract/syno_extract_system_patch
chmod +x /run/extract/syno_extract_system_patch
fi
rm -rf "$TMP" && mkdir -p "$TMP"
info "Install: Downloading $BASE.pat..."
MSG="Downloading DSM"
ERR="Failed to download $URL"
html "$MSG..."
PAT="/$BASE.pat"
@ -145,10 +240,6 @@ rm -f "$PAT"
if [[ "$URL" == "file://"* ]]; then
if [ ! -f "${URL:7}" ]; then
error "File '${URL:7}' does not exist!" && exit 65
fi
cp "${URL:7}" "$PAT"
else
@ -179,7 +270,7 @@ if ((SIZE<250000000)); then
error "The specified PAT file is probably an update pack as it's too small." && exit 62
fi
MSG="Extracting installation image..."
MSG="Extracting downloaded image..."
info "Install: $MSG" && html "$MSG"
if { tar tf "$PAT"; } >/dev/null 2>&1; then
@ -188,15 +279,22 @@ if { tar tf "$PAT"; } >/dev/null 2>&1; then
else
{ (cd "$TMP" && python3 /run/extract.py -i "$PAT" -d 2>/run/extract.log); rc=$?; } || :
export LD_LIBRARY_PATH="/run/extract"
if (( rc != 0 )); then
cat /run/extract.log
error "Failed to extract PAT file, reason $rc" && exit 63
if [ "$ARCH" == "amd64" ]; then
{ /run/extract/syno_extract_system_patch "$PAT" "$TMP/."; rc=$?; } || :
else
{ qemu-x86_64 /run/extract/syno_extract_system_patch "$PAT" "$TMP/."; rc=$?; } || :
fi
export LD_LIBRARY_PATH=""
(( rc != 0 )) && error "Failed to extract PAT file, reason $rc" && exit 63
fi
rm -rf /run/extract
MSG="Preparing system partition..."
info "Install: $MSG" && html "$MSG"
@ -270,9 +368,12 @@ mv "$HDA.tgz" "$HDA.txz"
[ -d "$PKG" ] && mv "$PKG/" "$MOUNT/.SynoUpgradePackages/"
rm -f "$MOUNT/.SynoUpgradePackages/ActiveInsight-"*
[ -s "$HDP.txz" ] && tar xpfJ "$HDP.txz" --absolute-names -C "$MOUNT/"
if [ -s "$IDB.txz" ]; then
INDEX_DB="$MOUNT/usr/syno/synoman/indexdb"
INDEX_DB="$MOUNT/usr/syno/synoman/indexdb/"
mkdir -p "$INDEX_DB"
tar xpfJ "$IDB.txz" --absolute-names -C "$INDEX_DB"
fi
LABEL="1.44.1-42218"
@ -280,12 +381,22 @@ OFFSET="1048576" # 2048 * 512
NUMBLOCKS="2097152" # (16777216 * 512) / 4096
MSG="Installing system partition..."
fakeroot -- bash -c "set -Eeu;\
[ -s $HDP.txz ] && tar xpfJ $HDP.txz --absolute-names -C $MOUNT/;\
[ -s $IDB.txz ] && tar xpfJ $IDB.txz --absolute-names -C $INDEX_DB/;\
tar xpfJ $HDA.txz --absolute-names --skip-old-files -C $MOUNT/;\
printf '%b%s%b' '\E[1;34m \E[1;36m' 'Install: $MSG' '\E[0m\n';\
mke2fs -q -t ext4 -b 4096 -d $MOUNT/ -L $LABEL -F -E offset=$OFFSET $SYSTEM $NUMBLOCKS"
if [[ "$ROOT" != [Nn]* ]]; then
tar xpfJ "$HDA.txz" --absolute-names --skip-old-files -C "$MOUNT/"
info "Install: $MSG" && html "$MSG"
mke2fs -q -t ext4 -b 4096 -d "$MOUNT/" -L "$LABEL" -F -E "offset=$OFFSET" "$SYSTEM" "$NUMBLOCKS"
else
fakeroot -- bash -c "set -Eeu;\
tar xpfJ $HDA.txz --absolute-names --skip-old-files -C $MOUNT/;\
printf '%b%s%b' '\E[1;34m \E[1;36m' 'Install: $MSG' '\E[0m\n';\
mke2fs -q -t ext4 -b 4096 -d $MOUNT/ -L $LABEL -F -E offset=$OFFSET $SYSTEM $NUMBLOCKS"
fi
rm -rf "$MOUNT"
echo "$BASE" > "$STORAGE/dsm.ver"

View File

@ -104,21 +104,15 @@ configureDHCP() {
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
# dnsmasq configuration:
DNSMASQ_OPTS+=" --dhcp-authoritative"
# Set DHCP range and host
DNSMASQ_OPTS+=" --dhcp-range=$VM_NET_IP,$VM_NET_IP"
DNSMASQ_OPTS+=" --dhcp-host=$VM_NET_MAC,,$VM_NET_IP,$VM_NET_HOST,infinite"
# Set DNS server and gateway
DNSMASQ_OPTS+=" --dhcp-option=option:netmask,255.255.255.0"
DNSMASQ_OPTS+=" --dhcp-option=option:router,${VM_NET_IP%.*}.1"
DNSMASQ_OPTS+=" --dhcp-option=option:dns-server,${VM_NET_IP%.*}.1"
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"
@ -176,11 +170,7 @@ getHostPorts() {
configureUser() {
if [ -z "$IP6" ]; then
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"
else
NET_OPTS="-netdev user,id=hostnet0,ipv4=on,host=${VM_NET_IP%.*}.1,net=${VM_NET_IP%.*}.0/24,dhcpstart=$VM_NET_IP,ipv6=on,hostname=$VM_NET_HOST"
fi
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")
@ -196,7 +186,6 @@ configureNAT() {
# Create the necessary file structure for /dev/net/tun
if [ ! -c /dev/net/tun ]; then
[[ "$PODMAN" == [Yy1]* ]] && return 1
[ ! -d /dev/net ] && mkdir -m 755 /dev/net
if mknod /dev/net/tun c 10 200; then
chmod 666 /dev/net/tun
@ -209,11 +198,9 @@ configureNAT() {
# Check port forwarding flag
if [[ $(< /proc/sys/net/ipv4/ip_forward) -eq 0 ]]; then
{ sysctl -w net.ipv4.ip_forward=1 > /dev/null 2>&1; rc=$?; } || :
{ sysctl -w net.ipv4.ip_forward=1 > /dev/null; rc=$?; } || :
if (( rc != 0 )) || [[ $(< /proc/sys/net/ipv4/ip_forward) -eq 0 ]]; then
[[ "$PODMAN" == [Yy1]* ]] && return 1
error "IP forwarding is disabled. $ADD_ERR --sysctl net.ipv4.ip_forward=1"
return 1
error "IP forwarding is disabled. $ADD_ERR --sysctl net.ipv4.ip_forward=1" && return 1
fi
fi
@ -343,17 +330,17 @@ closeNetwork() {
checkOS() {
local kernel
local name
local os=""
local if="macvlan"
kernel=$(uname -a)
name=$(uname -a)
[[ "${kernel,,}" == *"darwin"* ]] && os="Docker Desktop for macOS"
[[ "${kernel,,}" == *"microsoft"* ]] && os="Docker Desktop for Windows"
[[ "${name,,}" == *"darwin"* ]] && os="Docker Desktop for macOS"
[[ "${name,,}" == *"microsoft"* ]] && os="Docker Desktop for Windows"
if [[ "$DHCP" == [Yy1]* ]]; then
if="macvtap"
[[ "${kernel,,}" == *"synology"* ]] && os="Synology Container Manager"
[[ "${name,,}" == *"synology"* ]] && os="Synology Container Manager"
fi
if [ -n "$os" ]; then
@ -378,15 +365,9 @@ getInfo() {
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
error "$ADD_ERR -e \"VM_NET_DEV=NAME\" to specify another interface name." && exit 27
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
@ -404,7 +385,6 @@ getInfo() {
if [ -z "$VM_NET_MAC" ]; then
local file="$STORAGE/dsm.mac"
[ -s "$file" ] && VM_NET_MAC=$(<"$file")
VM_NET_MAC="${VM_NET_MAC//[![:print:]]/}"
if [ -z "$VM_NET_MAC" ]; then
# Generate MAC address based on Docker container ID in hostname
VM_NET_MAC=$(echo "$HOST" | md5sum | sed 's/^\(..\)\(..\)\(..\)\(..\)\(..\).*$/02:11:32:\3:\4:\5/')
@ -434,7 +414,6 @@ getInfo() {
[ -n "$IP6" ] && IP6=$(echo "$IP6" | sed -e's/^.*inet6 \([^ ]*\)\/.*$/\1/;t;d' | head -n 1)
fi
[ -f "/run/.containerenv" ] && PODMAN="Y" || PODMAN="N"
echo "$IP" > /run/shm/qemu.ip
return 0
@ -457,10 +436,7 @@ if [[ "$DEBUG" == [Yy1]* ]]; then
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
[ -f /etc/resolv.conf ] && grep '^nameserver*' /etc/resolv.conf
echo
fi
@ -504,14 +480,7 @@ else
closeBridge
NETWORK="user"
msg="falling back to user-mode networking!"
if [[ "$PODMAN" != [Yy1]* ]]; then
msg="an error occured, $msg"
else
msg="podman detected, $msg"
fi
warn "$msg"
[ -z "$USER_PORTS" ] && info "Notice: port mapping will not work without \"USER_PORTS\" now."
warn "falling back to user-mode networking! Performance will be bad and port mapping will not work."
fi

View File

@ -10,20 +10,19 @@ set -Eeuo pipefail
: "${DEF_MODEL:="qemu64"}"
CLOCKSOURCE="tsc"
[[ "${ARCH,,}" == "arm64" ]] && CLOCKSOURCE="arch_sys_counter"
[[ "${ARCH,,}" == "arm64" ]] && CLOCKSOURCE="arch_sys_counter"
CLOCK="/sys/devices/system/clocksource/clocksource0/current_clocksource"
if [ ! -f "$CLOCK" ]; then
warn "file \"$CLOCK\" cannot not found?"
else
result=$(<"$CLOCK")
result="${result//[![:print:]]/}"
case "${result,,}" in
"${CLOCKSOURCE,,}" ) ;;
"kvm-clock" ) info "Nested KVM virtualization detected.." ;;
"hyperv_clocksource_tsc_page" ) info "Nested Hyper-V virtualization detected.." ;;
"hpet" ) warn "unsupported clock source detected: '$result'. Please set host clock source to '$CLOCKSOURCE'." ;;
*) warn "unexpected clock source detected: '$result'. Please set host clock source to '$CLOCKSOURCE'." ;;
"hpet" ) warn "unsupported clock source detected: '$result'. Please set host clock source to '$CLOCKSOURCE'" ;;
*) warn "unexpected clock source detected: '$result'. Please set host clock source to '$CLOCKSOURCE'" ;;
esac
fi
@ -37,14 +36,14 @@ if [[ "$KVM" != [Nn]* ]]; then
KVM_ERR=""
if [ ! -e /dev/kvm ]; then
KVM_ERR="(/dev/kvm is missing)"
KVM_ERR="(device file missing)"
else
if ! sh -c 'echo -n > /dev/kvm' &> /dev/null; then
KVM_ERR="(/dev/kvm is unwriteable)"
KVM_ERR="(no write access)"
else
flags=$(sed -ne '/^flags/s/^.*: //p' /proc/cpuinfo)
if ! grep -qw "vmx\|svm" <<< "$flags"; then
KVM_ERR="(not enabled in BIOS)"
KVM_ERR="(vmx/svm disabled)"
fi
fi
fi
@ -53,17 +52,9 @@ if [[ "$KVM" != [Nn]* ]]; then
KVM="N"
if [[ "$OSTYPE" =~ ^darwin ]]; then
warn "you are using macOS which has no KVM support, this will cause a major loss of performance."
else
kernel=$(uname -a)
case "${kernel,,}" in
*"microsoft"* )
error "Please bind '/dev/kvm' as a volume in the optional container settings when using Docker Desktop." ;;
*"synology"* )
error "Please make sure that Synology VMM (Virtual Machine Manager) is installed and that '/dev/kvm' is binded to this container." ;;
*)
error "KVM acceleration is not available $KVM_ERR, this will cause a major loss of performance."
error "See the FAQ for possible causes, or continue without it by adding KVM: \"N\" (not recommended)." ;;
esac
else
error "KVM acceleration not available $KVM_ERR, this will cause a major loss of performance."
error "See the FAQ on how to diagnose the cause, or continue without KVM by setting KVM=N (not recommended)."
[[ "$DEBUG" != [Yy1]* ]] && exit 88
fi
fi

View File

@ -26,7 +26,7 @@ do
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/')
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%"

View File

@ -1,6 +1,10 @@
#!/usr/bin/env bash
set -Eeuo pipefail
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; }
trap 'error "Status $? while: $BASH_COMMAND (line $LINENO/$BASH_LINENO)"' ERR
[ ! -f "/run/entry.sh" ] && error "Script must run inside Docker container!" && exit 11
@ -17,8 +21,8 @@ echo " For support visit $SUPPORT"
: "${CONSOLE:="N"}" # Disable console mode
: "${ALLOCATE:=""}" # Preallocate diskspace
: "${ARGUMENTS:=""}" # Extra QEMU parameters
: "${CPU_CORES:="2"}" # Amount of CPU cores
: "${RAM_SIZE:="2G"}" # Maximum RAM amount
: "${CPU_CORES:="1"}" # Amount of CPU cores
: "${RAM_SIZE:="1G"}" # Maximum RAM amount
: "${RAM_CHECK:="Y"}" # Check available RAM
: "${DISK_SIZE:="16G"}" # Initial data disk size
: "${STORAGE:="/storage"}" # Storage folder location
@ -34,7 +38,7 @@ TEMPLATE="/var/www/index.html"
FOOTER1="$APP for Docker v$(</run/version)"
FOOTER2="<a href='$SUPPORT'>$SUPPORT</a>"
CPU=$(cpu)
CPI=$(lscpu)
SYS=$(uname -r)
HOST=$(hostname -s)
KERNEL=$(echo "$SYS" | cut -b 1)
@ -42,12 +46,41 @@ MINOR=$(echo "$SYS" | cut -d '.' -f2)
ARCH=$(dpkg --print-architecture)
CORES=$(grep -c '^processor' /proc/cpuinfo)
if ! grep -qi "socket(s)" <<< "$(lscpu)"; then
if ! grep -qi "socket(s)" <<< "$CPI"; then
SOCKETS=1
else
SOCKETS=$(lscpu | grep -m 1 -i 'socket(s)' | awk '{print $(2)}')
SOCKETS=$(echo "$CPI" | grep -m 1 -i 'socket(s)' | awk '{print $(2)}')
fi
if ! grep -qi "model name" <<< "$CPI"; then
CPU=""
else
CPU=$(echo "$CPI" | 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:" <<< "$CPI"; then
CPU=$(echo "$CPI" | 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// 6 Core/}"
CPU="${CPU// 8 Core/}"
CPU="${CPU// 16 Core/}"
CPU="${CPU// 32 Core/}"
CPU="${CPU// 64 Core/}"
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// Core TM/ Core}"
CPU="${CPU// with Radeon Graphics/}"
CPU="${CPU// with Radeon Vega Graphics/}"
[ -z "${CPU// /}" ] && CPU="Unknown"
[ -n "${CPU_CORES//[0-9 ]}" ] && error "Invalid amount of CPU_CORES: $CPU_CORES" && exit 15
# Check system
@ -77,6 +110,30 @@ if [[ "${FS,,}" == "ecryptfs" ]] || [[ "${FS,,}" == "tmpfs" ]]; then
DISK_CACHE="writeback"
fi
formatBytes() {
local result
result=$(numfmt --to=iec "$1")
local unit="${result//[0-9. ]}"
if [ -z "$unit" ]; then
unit="bytes"
else
unit=$(echo "${unit^^}" | sed 's/K/KB/g;s/M/MB/g;s/G/GB/g;s/T/TB/g')
fi
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
}
# Read memory
RAM_SPARE=500000000
RAM_AVAIL=$(free -b | grep -m 1 Mem: | awk '{print $7}')
@ -124,6 +181,91 @@ rm -f /run/shm/dsm.url
rm -rf /tmp/dsm
rm -rf "$STORAGE/tmp"
# Helper functions
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
}
getCountry() {
local url=$1
local query=$2

View File

@ -1,175 +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// 48 Core/}"
cpu="${cpu// 64 Core/}"
cpu="${cpu// 96 Core/}"
cpu="${cpu// 128 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/}"
cpu="${cpu// with Radeon Vega Mobile Gfx/}"
[ -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