Compare commits

..

77 Commits

Author SHA1 Message Date
Kroese
705c6ce7f1 fix: Exclude 'tap' from bus check (#1043) 2025-10-05 17:06:57 +02:00
Kroese
f2937ab507 feat: Allow large MTU sizes (#1042) 2025-10-04 10:35:20 +02:00
Kroese
399829cf3c feat: Make monitor port configurable (#1041) 2025-10-04 09:39:20 +02:00
xrh0905
b694d6faf8 feat: Support 8k sector sizes (#1040) 2025-10-03 12:57:08 +02:00
Kroese
7acd1f6cdb feat: Enhanced Dnsmasq logging (#1039) 2025-10-03 01:54:44 +02:00
Kroese
09ca3bf118 feat: Add debug trace option (#1038) 2025-10-02 17:18:53 +02:00
renovate[bot]
6cac45c397 chore(deps): update peter-evans/dockerhub-description action to v5 (#1037)
Some checks failed
Update / dockerHubDescription (push) Has been cancelled
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-01 23:39:30 +02:00
Kroese
f18663d840 feat: Network mode detection (#1036) 2025-10-01 13:05:13 +02:00
Kroese
fefe1af9e6 fix: CPU detection (#1035)
Refactor CPU string processing to remove 'th Gen' suffix.
2025-09-30 17:18:43 +02:00
Kroese
87a8cf7513 feat: Support 32k sector sizes (#1034) 2025-09-30 10:49:07 +02:00
Kroese
7f31cb6023 fix: Detect host mode networking (#1033) 2025-09-30 10:32:00 +02:00
Kroese
138742c953 feat: Increase default disksize (#1030)
Some checks failed
Update / dockerHubDescription (push) Has been cancelled
2025-09-28 18:22:44 +02:00
Kroese
2c6efc45f2 feat: Make webserver port configurable (#1028) 2025-09-27 11:44:13 +02:00
Kroese
24d795fbe3 buid: Add ethtool package (#1027) 2025-09-27 10:45:09 +02:00
Kroese
7fae62d286 feat: Detect host mode networking (#1026) 2025-09-27 10:44:02 +02:00
Kroese
2135df07ea docs: Additional info for user-mode networking (#1025) 2025-09-27 10:08:11 +02:00
Kroese
521beedf1c feat: Add note for MAC address availability (#1024) 2025-09-27 09:49:11 +02:00
Kroese
e362c9a8a9 feat: Update error message for KVM acceleration (#1023) 2025-09-24 16:10:32 +02:00
Kroese
78817ecfc1 fix: Remove default model (#1022) 2025-09-23 16:04:44 +02:00
Kroese
8de7f56ff8 feat: Add KVM warning (#1021) 2025-09-23 16:02:42 +02:00
Kroese
2e2017470e fix: Syntax for arithmetic operations (#1020) 2025-09-22 20:24:23 +02:00
Kroese
0a0cd98de3 feat: Add "max" setting to automaticly set CPU cores and RAM (#1019) 2025-09-22 16:59:02 +02:00
renovate[bot]
17187dd23a chore(deps): update hadolint/hadolint-action action to v3.3.0 (#1018)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-22 16:56:58 +02:00
Kroese
10237b31cf revert: Simplify conditional checks (#1017)
This reverts commit 6883efb857.
2025-09-21 23:08:00 +02:00
Kroese
6883efb857 fix: Simplify conditional checks (#1016) 2025-09-21 15:09:52 +02:00
Kroese
1ca55cad8f feat: Limit CPU_CORES to amount of physical cores (#1015) 2025-09-21 13:41:20 +02:00
Kroese
f841eb1ef1 fix: Simplify conditional checks (#1014) 2025-09-20 23:47:00 +02:00
Kroese
1ee49332f3 feat: Improve CPU detection (#1013) 2025-09-20 21:43:35 +02:00
Kroese
095e618785 feat: Make webserver optional (#1012) 2025-09-18 23:45:05 +02:00
Kroese
57a902ad9f feat: add UDP support to USER_PORTS (#1011)
Allow USER_PORTS entries in the form PORT or PORT/PROTO (tcp or udp). When the protocol is omitted, TCP is assumed for backward compatibility. This enables forwarding of UDP services when running the container in user‑mode networking.
2025-09-17 21:49:20 +02:00
xrh0905
a7e229aaae feat: Add IPQuery.io as additional comparison source for the country code (#1006) 2025-09-17 17:55:54 +02:00
Kroese
10466d7851 feat: Parse CPU flags (#1010) 2025-09-17 17:54:50 +02:00
Kroese
238ebd273b build: Disable automatic builds (#1009)
Removed push triggers and paths to ignore from build workflow.
2025-09-14 11:54:51 +02:00
renovate[bot]
0b08f4212e chore(deps): update hadolint/hadolint-action action to v3.2.0 (#1008)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-03 16:43:41 +02:00
Kroese
9aec5d20e3 feat: Check if storage folder is writeable (#1005)
Some checks failed
Build / Check (push) Has been cancelled
Update / dockerHubDescription (push) Has been cancelled
Build / Build (push) Has been cancelled
2025-08-27 22:50:23 +02:00
Kroese
a19bf2f066 feat: Check if storage folder is writeable (#1004) 2025-08-27 22:48:23 +02:00
Kroese
bee68ee548 feat: Add syntax parser directive (#1003) 2025-08-27 21:29:28 +02:00
xrh0905
520c70ab22 feat: Allow shutdown timeout override (#995)
Mitigation #987
2025-08-27 19:58:02 +02:00
dependabot[bot]
67a7fbc94b build(deps): Bump actions/checkout from 4 to 5 (#1001)
Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 5.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-27 19:56:41 +02:00
Kroese
1b8054e847 fix: Podman detection (#990)
Some checks failed
Build / Check (push) Has been cancelled
Build / Build (push) Has been cancelled
2025-05-27 00:50:40 +02:00
Kroese
631a558a9f feat: Enable IPv6 support for user-mode container networking (#983)
Some checks failed
Build / Check (push) Has been cancelled
Build / Build (push) Has been cancelled
2025-04-27 11:28:54 +02:00
Kroese
d5805b4e08 feat: Check CPU vendor (#982) 2025-04-27 11:21:37 +02:00
Kroese
1dc15ce2e0 docs: Add input types (#981) 2025-04-23 12:54:22 +02:00
Kroese
4145e811df feat: Improve CPU detection (#980)
Some checks failed
Build / Check (push) Has been cancelled
Build / Build (push) Has been cancelled
2025-04-20 21:43:02 +02:00
Kroese
fe8615d7d3 docs: Add quotes around $PWD (#977)
Some checks failed
Build / Check (push) Has been cancelled
Update / dockerHubDescription (push) Has been cancelled
Build / Build (push) Has been cancelled
2025-04-16 12:10:59 +02:00
Kroese
27ea5506bc feat: Default to 2 CPU cores and 2GB of RAM (#976) 2025-04-16 11:56:02 +02:00
Kroese
394131a0d7 feat: Podman detection (#972)
Some checks failed
Build / Check (push) Has been cancelled
Build / Build (push) Has been cancelled
2025-04-09 09:01:01 +02:00
Kroese
4d0d16023f feat: Podman detection (#971) 2025-04-09 08:58:02 +02:00
Kroese
60dd794b29 fix: Avoid pipe to head on find (#970) 2025-04-09 08:03:41 +02:00
Kroese
f13d104968 build: Add root-user-action flag (#968)
Some checks are pending
Build / Check (push) Waiting to run
Build / Build (push) Blocked by required conditions
2025-04-08 07:53:17 +02:00
Kroese
914099fd12 build: Add --root-user-action flag (#967)
Some checks are pending
Build / Check (push) Waiting to run
Build / Build (push) Blocked by required conditions
2025-04-07 18:47:36 +02:00
Kroese
639725957d fix: Permission errors on QNAP (#966) 2025-04-07 18:36:47 +02:00
Kroese
64bbe82c4a fix: KVM warning (#965) 2025-04-07 17:44:26 +02:00
Kroese
73a13e5697 fix: QNAP permission errors (#964) 2025-04-07 17:20:14 +02:00
Kroese
e8ec5fb8ed feat: Support 4k sector sizes (#963)
Some checks failed
Build / Check (push) Waiting to run
Build / Build (push) Blocked by required conditions
Update / dockerHubDescription (push) Has been cancelled
2025-04-07 13:25:20 +02:00
Kroese
0b500ca377 docs: Disk pass-through (#960)
Some checks failed
Update / dockerHubDescription (push) Has been cancelled
2025-04-03 10:22:26 +02:00
Kroese
df58745ed8 fix: Ignore missing custom .pat after install (#959)
Some checks failed
Build / Check (push) Has been cancelled
Build / Build (push) Has been cancelled
2025-04-03 01:13:14 +02:00
Kroese
55e8ab4930 docs: Github Codespaces (#956)
Some checks failed
Update / dockerHubDescription (push) Has been cancelled
2025-03-27 01:48:40 +01:00
Kroese
4882fd3bf6 fix: Local file support (#955)
Some checks failed
Build / Check (push) Has been cancelled
Build / Build (push) Has been cancelled
2025-03-26 19:51:58 +01:00
Kroese
3e69f4bcc9 feat: New extraction method (#954)
Some checks are pending
Build / Check (push) Waiting to run
Build / Build (push) Blocked by required conditions
2025-03-26 09:24:13 +01:00
Kroese
39428909d6 docs: Installation (#953)
Some checks are pending
Update / dockerHubDescription (push) Waiting to run
2025-03-26 02:47:28 +01:00
Kroese
71d2ed40db docs: Github Codespaces (#952)
Some checks are pending
Update / dockerHubDescription (push) Waiting to run
2025-03-25 14:49:46 +01:00
Kroese
9ad21a28a6 docs: Disk pass-through (#951)
Some checks are pending
Update / dockerHubDescription (push) Waiting to run
2025-03-25 12:18:38 +01:00
Kroese
0c7acd6e71 fix: Remove non-printable characters (#949)
Some checks failed
Build / Check (push) Has been cancelled
Build / Build (push) Has been cancelled
2025-03-24 13:52:38 +01:00
Kroese
ad26129375 docs: KVM information (#947)
Some checks failed
Update / dockerHubDescription (push) Has been cancelled
2025-03-20 23:21:41 +01:00
Kroese
4e7822fedd docs: Compatibility chart (#946) 2025-03-20 23:07:14 +01:00
Kroese
4dfcbe4ab1 docs: Add Podman (#945) 2025-03-20 20:09:53 +01:00
Kroese
8fb6f1f9ad feat: Podman detection (#944)
Some checks failed
Build / Check (push) Has been cancelled
Build / Build (push) Has been cancelled
2025-03-20 11:54:26 +01:00
Kroese
11d4fafa6d fix: User-mode networking (#943)
Some checks are pending
Build / Check (push) Waiting to run
Build / Build (push) Blocked by required conditions
2025-03-20 03:07:01 +01:00
Kroese
be15557798 fix: User-mode networking (#942) 2025-03-20 03:05:50 +01:00
Kroese
1e83757494 fix: Set user-mode IP address (#941)
Some checks are pending
Build / Check (push) Waiting to run
Build / Build (push) Blocked by required conditions
2025-03-19 12:55:53 +01:00
Kroese
fad463a439 feat: Add devcontainer (#940)
Some checks are pending
Build / Check (push) Waiting to run
Build / Build (push) Blocked by required conditions
2025-03-19 09:17:48 +01:00
Kroese
608563d029 feat: Add devcontainer (#939)
Some checks are pending
Build / Check (push) Waiting to run
Build / Build (push) Blocked by required conditions
2025-03-18 19:25:27 +01:00
Kroese
5fcd22b09f docs: Formatting (#938)
Some checks failed
Build / Check (push) Waiting to run
Build / Build (push) Blocked by required conditions
Update / dockerHubDescription (push) Has been cancelled
2025-03-18 14:24:05 +01:00
Kroese
65548da2ef docs: Github Codespaces (#937) 2025-03-18 14:10:08 +01:00
Kroese
111e513dac docs: Github Codespaces (#936) 2025-03-18 14:09:10 +01:00
Kroese
7fce3a98fe feat: Refactor helper functions (#935) 2025-03-18 12:57:52 +01:00
22 changed files with 567 additions and 508 deletions

6
.devcontainer.json Normal file
View File

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

View File

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

View File

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

View File

@@ -2,20 +2,6 @@ name: Build
on: on:
workflow_dispatch: workflow_dispatch:
push:
branches:
- master
paths-ignore:
- '**/*.md'
- '**/*.yml'
- '**/*.js'
- '**/*.css'
- '**/*.html'
- 'web/**'
- '.gitignore'
- '.dockerignore'
- '.github/**'
- '.github/workflows/**'
concurrency: concurrency:
group: build group: build
@@ -36,7 +22,7 @@ jobs:
steps: steps:
- -
name: Checkout name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v5
with: with:
fetch-depth: 0 fetch-depth: 0
- -

View File

@@ -9,7 +9,7 @@ jobs:
steps: steps:
- -
name: Checkout name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v5
- -
name: Run ShellCheck name: Run ShellCheck
uses: ludeeus/action-shellcheck@master uses: ludeeus/action-shellcheck@master
@@ -17,8 +17,8 @@ jobs:
SHELLCHECK_OPTS: -x --source-path=src -e SC2001 -e SC2034 -e SC2064 -e SC2317 -e SC2153 -e SC2028 SHELLCHECK_OPTS: -x --source-path=src -e SC2001 -e SC2034 -e SC2064 -e SC2317 -e SC2153 -e SC2028
- -
name: Lint Dockerfile name: Lint Dockerfile
uses: hadolint/hadolint-action@v3.1.0 uses: hadolint/hadolint-action@v3.3.0
with: with:
dockerfile: Dockerfile dockerfile: Dockerfile
ignore: DL3008,DL3003,DL3006 ignore: DL3008,DL3003,DL3006,DL3013
failure-threshold: warning failure-threshold: warning

View File

@@ -12,10 +12,10 @@ jobs:
dockerHubDescription: dockerHubDescription:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v5
- -
name: Docker Hub Description name: Docker Hub Description
uses: peter-evans/dockerhub-description@v4 uses: peter-evans/dockerhub-description@v5
with: with:
username: ${{ secrets.DOCKERHUB_USERNAME }} username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }} password: ${{ secrets.DOCKERHUB_TOKEN }}

View File

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

View File

@@ -3,7 +3,7 @@ services:
container_name: dsm container_name: dsm
image: vdsm/virtual-dsm image: vdsm/virtual-dsm
environment: environment:
DISK_SIZE: "16G" DISK_SIZE: "256G"
devices: devices:
- /dev/kvm - /dev/kvm
- /dev/net/tun - /dev/net/tun

View File

@@ -8,7 +8,7 @@ spec:
- ReadWriteOnce - ReadWriteOnce
resources: resources:
requests: requests:
storage: 16Gi storage: 256Gi
--- ---
apiVersion: apps/v1 apiVersion: apps/v1
kind: Deployment kind: Deployment
@@ -31,7 +31,7 @@ spec:
image: vdsm/virtual-dsm image: vdsm/virtual-dsm
env: env:
- name: DISK_SIZE - name: DISK_SIZE
value: "16G" value: "256G"
ports: ports:
- containerPort: 5000 - containerPort: 5000
name: http name: http

View File

@@ -22,7 +22,7 @@ Virtual DSM in a Docker container.
## Usage 🐳 ## Usage 🐳
Via Docker Compose: ##### Via Docker Compose:
```yaml ```yaml
services: services:
@@ -30,7 +30,7 @@ services:
container_name: dsm container_name: dsm
image: vdsm/virtual-dsm image: vdsm/virtual-dsm
environment: environment:
DISK_SIZE: "16G" DISK_SIZE: "256G"
devices: devices:
- /dev/kvm - /dev/kvm
- /dev/net/tun - /dev/net/tun
@@ -44,27 +44,21 @@ services:
stop_grace_period: 2m stop_grace_period: 2m
``` ```
Via Docker CLI: ##### Via Docker CLI:
```bash ```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 -e "DISK_SIZE=256G" -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 ```shell
kubectl apply -f https://raw.githubusercontent.com/vdsm/virtual-dsm/refs/heads/master/kubernetes.yml kubectl apply -f https://raw.githubusercontent.com/vdsm/virtual-dsm/refs/heads/master/kubernetes.yml
``` ```
## Compatibility ⚙️ ##### Via Github Codespaces:
| **Product** | **Platform** | | [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/vdsm/virtual-dsm)
|---|---|---|
| Docker Engine | Linux| ✅ |
| Docker Desktop | Linux | ❌ |
| Docker Desktop | macOS | ❌ |
| Docker Desktop | Windows 11 | ✅ |
| Docker Desktop | Windows 10 | ❌ |
## FAQ 💬 ## FAQ 💬
@@ -93,35 +87,24 @@ kubectl apply -f https://raw.githubusercontent.com/vdsm/virtual-dsm/refs/heads/m
### How do I change the size of the disk? ### How do I change the size of the disk?
To expand the default size of 16 GB, locate the `DISK_SIZE` setting in your compose file and modify it to your preferred capacity: To expand the default size of 256 GB, locate the `DISK_SIZE` setting in your compose file and modify it to your preferred capacity:
```yaml ```yaml
environment: environment:
DISK_SIZE: "128G" DISK_SIZE: "512G"
``` ```
> [!TIP] > [!TIP]
> This can also be used to resize the existing disk to a larger capacity without any data loss. > This can also be used to resize the existing disk to a larger capacity without any data loss.
### How do I create a growable disk?
By default, the entire capacity of the disk will be reserved in advance.
To create a growable disk that only allocates space that is actually used, add the following environment variable:
```yaml
environment:
DISK_FMT: "qcow2"
```
### How do I add multiple disks? ### How do I add multiple disks?
To create additional disks, modify your compose file like this: To create additional disks, modify your compose file like this:
```yaml ```yaml
environment: environment:
DISK2_SIZE: "32G" DISK2_SIZE: "500G"
DISK3_SIZE: "64G" DISK3_SIZE: "750G"
volumes: volumes:
- ./example2:/storage2 - ./example2:/storage2
- ./example3:/storage3 - ./example3:/storage3
@@ -129,25 +112,19 @@ kubectl apply -f https://raw.githubusercontent.com/vdsm/virtual-dsm/refs/heads/m
### How do I pass-through a disk? ### How do I pass-through a disk?
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. It is possible to pass-through disk devices or partitions directly by adding them to your compose file in this way:
You can add the virtual device to your compose file like this:
```yaml ```yaml
devices: devices:
- /dev/disk/by-uuid/12345-12345-12345-12345-12345:/disk2 - /dev/sdb:/disk1
- /dev/sdc1:/disk2
``` ```
The device needs to be totally empty (without any partition table) otherwise DSM does not always format it into a volume. Make sure it is totally empty (without any filesystem), otherwise DSM may not format it as 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? ### How do I change the amount of CPU or RAM?
By default, the container will be allowed to use a maximum of 1 CPU core and 1 GB of RAM. By default, the container will be allowed to use a maximum of 2 CPU cores and 2 GB of RAM.
If you want to adjust this, you can specify the desired amount using the following environment variables: If you want to adjust this, you can specify the desired amount using the following environment variables:
@@ -159,9 +136,16 @@ kubectl apply -f https://raw.githubusercontent.com/vdsm/virtual-dsm/refs/heads/m
### How do I verify if my system supports KVM? ### How do I verify if my system supports KVM?
Only Linux and Windows 11 support KVM virtualization, macOS and Windows 10 do not unfortunately. First check if your software is compatible using this chart:
You can run the following commands in Linux to check your system: | **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:
```bash ```bash
sudo apt install cpu-checker sudo apt install cpu-checker
@@ -176,11 +160,7 @@ 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. - you are not using a cloud provider, as most of them do not allow nested virtualization for their VPS's.
If you do not receive any error from `kvm-ok` but the container still complains about KVM, please check whether: 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.
- 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? ### How do I assign an individual IP address to the container?
@@ -259,27 +239,19 @@ 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. With this method, it is even possible to switch back and forth between versions while keeping your file data intact.
If you don't have internet access, it's also possible to skip the download by setting `URL` to: Alternatively, you can also skip the download and use a local file instead, by binding it in your compose file in this way:
```yaml ```yaml
environment: volumes:
URL: "DSM_VirtualDSM_42218.pat" - ./DSM_VirtualDSM_42218.pat:/boot.pat
``` ```
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. 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.
### What are the differences compared to the standard DSM? ### What are the differences compared to the standard DSM?
There are only two minor differences: the Virtual Machine Manager package is not available, and Surveillance Station will not include any free licenses. There are only two minor differences: the Virtual Machine Manager package is not available, and Surveillance Station will not include any free licenses.
### How do I run Windows in a container?
You can use [dockur/windows](https://github.com/dockur/windows) for that. It shares many of the same features, and even has completely automatic installation.
### How do I run a Linux desktop in a container?
You can use [qemus/qemu](https://github.com/qemus/qemu) in that case.
### Is this project legal? ### Is this project legal?
Yes, this project contains only open-source code and does not distribute any copyrighted material. Neither does it try to circumvent any copyright protection measures. So under all applicable laws, this project will be considered legal. Yes, this project contains only open-source code and does not distribute any copyrighted material. Neither does it try to circumvent any copyright protection measures. So under all applicable laws, this project will be considered legal.

View File

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

View File

@@ -82,7 +82,7 @@ isCow() {
supportsDirect() { supportsDirect() {
local FS=$1 local FS=$1
if [[ "${FS,,}" == "ecryptfs" ]] || [[ "${FS,,}" == "tmpfs" ]]; then if [[ "${FS,,}" == "ecryptfs" || "${FS,,}" == "tmpfs" ]]; then
return 1 return 1
fi fi
@@ -320,7 +320,7 @@ convertDisk() {
msg="Conversion of $DISK_DESC" msg="Conversion of $DISK_DESC"
html "$msg completed..." html "$msg completed..."
info "$msg to $DST_FMT completed succesfully!" info "$msg to $DST_FMT completed successfully!"
return 0 return 0
} }
@@ -368,6 +368,8 @@ createDevice () {
local DISK_FMT=$5 local DISK_FMT=$5
local DISK_IO=$6 local DISK_IO=$6
local DISK_CACHE=$7 local DISK_CACHE=$7
local DISK_SERIAL=$8
local DISK_SECTORS=$9
local DISK_ID="data$DISK_INDEX" local DISK_ID="data$DISK_INDEX"
local index="" local index=""
@@ -381,29 +383,29 @@ createDevice () {
;; ;;
"usb" ) "usb" )
result+=",if=none \ result+=",if=none \
-device usb-storage,drive=${DISK_ID}${index}" -device usb-storage,drive=${DISK_ID}${index}${DISK_SERIAL}${DISK_SECTORS}"
echo "$result" echo "$result"
;; ;;
"nvme" ) "nvme" )
result+=",if=none \ result+=",if=none \
-device nvme,drive=${DISK_ID}${index},serial=deadbeaf${DISK_INDEX}" -device nvme,drive=${DISK_ID}${index},serial=deadbeaf${DISK_INDEX}${DISK_SERIAL}${DISK_SECTORS}"
echo "$result" echo "$result"
;; ;;
"ide" | "sata" ) "ide" | "sata" )
result+=",if=none \ result+=",if=none \
-device ich9-ahci,id=ahci${DISK_INDEX},addr=$DISK_ADDRESS \ -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}" -device ide-hd,drive=${DISK_ID},bus=ahci$DISK_INDEX.0,rotation_rate=$DISK_ROTATION${index}${DISK_SERIAL}${DISK_SECTORS}"
echo "$result" echo "$result"
;; ;;
"blk" | "virtio-blk" ) "blk" | "virtio-blk" )
result+=",if=none \ result+=",if=none \
-device virtio-blk-pci,drive=${DISK_ID},bus=pcie.0,addr=$DISK_ADDRESS,iothread=io2${index}" -device virtio-blk-pci,drive=${DISK_ID},bus=pcie.0,addr=$DISK_ADDRESS,iothread=io2${index}${DISK_SERIAL}${DISK_SECTORS}"
echo "$result" echo "$result"
;; ;;
"scsi" | "virtio-scsi" ) "scsi" | "virtio-scsi" )
result+=",if=none \ result+=",if=none \
-device virtio-scsi-pci,id=${DISK_ID}b,bus=pcie.0,addr=$DISK_ADDRESS,iothread=io2 \ -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}" -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}"
echo "$result" echo "$result"
;; ;;
esac esac
@@ -482,7 +484,7 @@ addDisk () {
fi 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 return 0
} }
@@ -497,12 +499,29 @@ addDevice () {
[ -z "$DISK_DEV" ] && return 0 [ -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 [ ! -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") 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" ]]; then
sectors=",logical_block_size=$logical,physical_block_size=$physical"
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")
return 0 return 0
} }
html "Initializing disks..." msg="Initializing disks..."
html "$msg"
[[ "$DEBUG" == [Yy1]* ]] && echo "$msg"
[ -z "${DISK_OPTS:-}" ] && DISK_OPTS="" [ -z "${DISK_OPTS:-}" ] && DISK_OPTS=""
[ -z "${DISK_TYPE:-}" ] && DISK_TYPE="scsi" [ -z "${DISK_TYPE:-}" ] && DISK_TYPE="scsi"
@@ -514,11 +533,7 @@ case "${DISK_TYPE,,}" in
esac esac
if [ -z "$ALLOCATE" ]; then if [ -z "$ALLOCATE" ]; then
if [[ "${DISK_FMT,,}" == "raw" ]]; then ALLOCATE="N"
ALLOCATE="Y"
else
ALLOCATE="N"
fi
fi fi
if [[ "$ALLOCATE" == [Nn]* ]]; then if [[ "$ALLOCATE" == [Nn]* ]]; then
@@ -529,11 +544,11 @@ else
DISK_ALLOC="preallocation=falloc" DISK_ALLOC="preallocation=falloc"
fi fi
DISK_OPTS+=$(createDevice "$BOOT" "$DISK_TYPE" "1" "0xa" "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") DISK_OPTS+=$(createDevice "$SYSTEM" "$DISK_TYPE" "2" "0xb" "raw" "$DISK_IO" "$DISK_CACHE" "" "")
DISK1_FILE="$STORAGE/${DISK_NAME}" DISK1_FILE="$STORAGE/${DISK_NAME}"
if [[ ! -f "$DISK1_FILE.img" ]] && [[ -f "$STORAGE/data${DISK_SIZE}.img" ]]; then if [ ! -f "$DISK1_FILE.img" ] && [ -f "$STORAGE/data${DISK_SIZE}.img" ]; then
# Fallback for legacy installs # Fallback for legacy installs
mv "$STORAGE/data${DISK_SIZE}.img" "$DISK1_FILE.img" mv "$STORAGE/data${DISK_SIZE}.img" "$DISK1_FILE.img"
fi fi
@@ -542,7 +557,7 @@ DISK2_FILE="/storage2/${DISK_NAME}2"
if [ ! -f "$DISK2_FILE.img" ]; then if [ ! -f "$DISK2_FILE.img" ]; then
# Fallback for legacy installs # Fallback for legacy installs
FALLBACK="/storage2/data.img" FALLBACK="/storage2/data.img"
if [[ -f "$DISK1_FILE.img" ]] && [[ -f "$FALLBACK" ]]; then if [[ -f "$DISK1_FILE.img" && -f "$FALLBACK" ]]; then
SIZE1=$(stat -c%s "$FALLBACK") SIZE1=$(stat -c%s "$FALLBACK")
SIZE2=$(stat -c%s "$DISK1_FILE.img") SIZE2=$(stat -c%s "$DISK1_FILE.img")
if [[ SIZE1 -ne SIZE2 ]]; then if [[ SIZE1 -ne SIZE2 ]]; then
@@ -555,7 +570,7 @@ DISK3_FILE="/storage3/${DISK_NAME}3"
if [ ! -f "$DISK3_FILE.img" ]; then if [ ! -f "$DISK3_FILE.img" ]; then
# Fallback for legacy installs # Fallback for legacy installs
FALLBACK="/storage3/data.img" FALLBACK="/storage3/data.img"
if [[ -f "$DISK1_FILE.img" ]] && [[ -f "$FALLBACK" ]]; then if [[ -f "$DISK1_FILE.img" && -f "$FALLBACK" ]]; then
SIZE1=$(stat -c%s "$FALLBACK") SIZE1=$(stat -c%s "$FALLBACK")
SIZE2=$(stat -c%s "$DISK1_FILE.img") SIZE2=$(stat -c%s "$DISK1_FILE.img")
if [[ SIZE1 -ne SIZE2 ]]; then if [[ SIZE1 -ne SIZE2 ]]; then

View File

@@ -8,7 +8,9 @@ set -Eeuo pipefail
: "${DISPLAY:="none"}" # Display type : "${DISPLAY:="none"}" # Display type
: "${RENDERNODE:="/dev/dri/renderD128"}" # Render node : "${RENDERNODE:="/dev/dri/renderD128"}" # Render node
if [[ "$GPU" != [Yy1]* ]] || [[ "$ARCH" != "amd64" ]]; then CPU_VENDOR=$(lscpu | awk '/Vendor ID/{print $3}')
if [[ "$GPU" != [Yy1]* || "$CPU_VENDOR" != "GenuineIntel" || "$ARCH" != "amd64" ]]; then
[[ "${DISPLAY,,}" == "none" ]] && VGA="none" [[ "${DISPLAY,,}" == "none" ]] && VGA="none"
DISPLAY_OPTS="-display $DISPLAY -vga $VGA" DISPLAY_OPTS="-display $DISPLAY -vga $VGA"
@@ -16,6 +18,10 @@ if [[ "$GPU" != [Yy1]* ]] || [[ "$ARCH" != "amd64" ]]; then
fi fi
msg="Configuring display drivers..."
html "$msg"
[[ "$DEBUG" == [Yy1]* ]] && echo "$msg"
DISPLAY_OPTS="-display egl-headless,rendernode=$RENDERNODE" DISPLAY_OPTS="-display egl-headless,rendernode=$RENDERNODE"
DISPLAY_OPTS+=" -vga $VGA" DISPLAY_OPTS+=" -vga $VGA"

View File

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

View File

@@ -5,29 +5,43 @@ set -Eeuo pipefail
if [ -f "$STORAGE/dsm.ver" ]; then if [ -f "$STORAGE/dsm.ver" ]; then
BASE=$(<"$STORAGE/dsm.ver") BASE=$(<"$STORAGE/dsm.ver")
BASE="${BASE//[![:print:]]/}"
[ -z "$BASE" ] && BASE="DSM_VirtualDSM_69057" [ -z "$BASE" ] && BASE="DSM_VirtualDSM_69057"
else else
# Fallback for old installs # Fallback for old installs
BASE="DSM_VirtualDSM_42962" BASE="DSM_VirtualDSM_42962"
fi fi
if [ -n "$URL" ]; then FN="boot.pat"
BASE=$(basename "$URL" .pat) DIR=$(find / -maxdepth 1 -type d -iname "$FN" -print -quit)
if [ ! -s "$STORAGE/$BASE.system.img" ]; then [ ! -d "$DIR" ] && DIR=$(find "$STORAGE" -maxdepth 1 -type d -iname "$FN" -print -quit)
BASE=$(basename "${URL%%\?*}" .pat)
: "${BASE//+/ }"; printf -v BASE '%b' "${_//%/\\x}" if [ -d "$DIR" ]; then
BASE=$(echo "$BASE" | sed -e 's/[^A-Za-z0-9._-]/_/g') BASE="DSM_VirtualDSM" && URL="file://$DIR"
fi if [[ ! -s "$STORAGE/$BASE.boot.img" || ! -s "$STORAGE/$BASE.system.img" ]]; then
if [[ "${URL,,}" != "http"* ]]; then error "The bind $DIR maps to a file that does not exist!" && exit 65
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
fi fi
if [[ -s "$STORAGE/$BASE.boot.img" ]] && [[ -s "$STORAGE/$BASE.system.img" ]]; then 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
BASE=$(basename "$URL" .pat)
if [ ! -s "$STORAGE/$BASE.system.img" ]; then
BASE=$(basename "${URL%%\?*}" .pat)
BASE="${BASE//+/ }"
printf -v BASE '%b' "${BASE//%/\\x}"
BASE="${BASE//[!A-Za-z0-9._-]/_}"
fi
if [[ "${URL,,}" != "http"* && "${URL,,}" != "file:"* ]] ; then
[ ! -s "$STORAGE/$BASE.pat" ] && error "Invalid URL: $URL" && exit 65
URL="file://$STORAGE/$BASE.pat"
fi
fi
if [[ -s "$STORAGE/$BASE.boot.img" && -s "$STORAGE/$BASE.system.img" ]]; then
return 0 # Previous installation found return 0 # Previous installation found
fi fi
@@ -46,11 +60,16 @@ if [ -z "$DL" ]; then
[[ "${COUNTRY^^}" == "CN" ]] && DL="$DL_CHINA" || DL="$DL_GLOBAL" [[ "${COUNTRY^^}" == "CN" ]] && DL="$DL_CHINA" || DL="$DL_GLOBAL"
fi fi
[ -z "$URL" ] && URL="$DL/release/7.2.2/72806/DSM_VirtualDSM_72806.pat" if [ -z "$URL" ]; then
URL="$DL/release/7.2.2/72806/DSM_VirtualDSM_72806.pat"
fi
BASE=$(basename "${URL%%\?*}" .pat) if [ ! -s "$FILE" ]; then
: "${BASE//+/ }"; printf -v BASE '%b' "${_//%/\\x}" BASE=$(basename "${URL%%\?*}" .pat)
BASE=$(echo "$BASE" | sed -e 's/[^A-Za-z0-9._-]/_/g') BASE="${BASE//+/ }"
printf -v BASE '%b' "${BASE//%/\\x}"
BASE="${BASE//[!A-Za-z0-9._-]/_}"
fi
if [[ "$URL" != "file://$STORAGE/$BASE.pat" ]]; then if [[ "$URL" != "file://$STORAGE/$BASE.pat" ]]; then
rm -f "$STORAGE/$BASE.pat" rm -f "$STORAGE/$BASE.pat"
@@ -71,7 +90,7 @@ if [[ "${FS,,}" == "fuse"* ]]; then
info "Warning: the filesystem of $STORAGE is FUSE, this extra layer will negatively affect performance!" info "Warning: the filesystem of $STORAGE is FUSE, this extra layer will negatively affect performance!"
fi fi
if [[ "${FS,,}" == "ecryptfs" ]] || [[ "${FS,,}" == "tmpfs" ]]; then if [[ "${FS,,}" == "ecryptfs" || "${FS,,}" == "tmpfs" ]]; then
info "Warning: the filesystem of $STORAGE is $FS, which does not support O_DIRECT mode, adjusting settings..." info "Warning: the filesystem of $STORAGE is $FS, which does not support O_DIRECT mode, adjusting settings..."
fi fi
@@ -111,128 +130,16 @@ else
PROGRESS="--progress=dot:giga" PROGRESS="--progress=dot:giga"
fi fi
# Download the required files from the Synology website if [[ "$URL" == "file://"* ]]; then
MSG="Copying DSM"
ROOT="Y" ERR="Failed to copy ${URL:7}"
RD="$TMP/rd.gz" info "Install: Copying installation image..."
RDC="$STORAGE/dsm.rd" else
MSG="Downloading DSM"
if [ ! -s "$RDC" ] && [[ "$URL" == "file://"* ]] && [[ "${URL,,}" == *"_42218.pat" ]]; then ERR="Failed to download $URL"
info "Install: Downloading $BASE.pat..."
rm -f "$RD"
rm -f "$RDC"
tar --extract --file="${URL:7}" --directory="$(dirname "$RD")"/. "$(basename "$RD")"
cp "$RD" "$RDC"
fi 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..." html "$MSG..."
PAT="/$BASE.pat" PAT="/$BASE.pat"
@@ -240,6 +147,10 @@ rm -f "$PAT"
if [[ "$URL" == "file://"* ]]; then if [[ "$URL" == "file://"* ]]; then
if [ ! -f "${URL:7}" ]; then
error "File '${URL:7}' does not exist!" && exit 65
fi
cp "${URL:7}" "$PAT" cp "${URL:7}" "$PAT"
else else
@@ -270,7 +181,7 @@ if ((SIZE<250000000)); then
error "The specified PAT file is probably an update pack as it's too small." && exit 62 error "The specified PAT file is probably an update pack as it's too small." && exit 62
fi fi
MSG="Extracting downloaded image..." MSG="Extracting installation image..."
info "Install: $MSG" && html "$MSG" info "Install: $MSG" && html "$MSG"
if { tar tf "$PAT"; } >/dev/null 2>&1; then if { tar tf "$PAT"; } >/dev/null 2>&1; then
@@ -279,22 +190,15 @@ if { tar tf "$PAT"; } >/dev/null 2>&1; then
else else
export LD_LIBRARY_PATH="/run/extract" { (cd "$TMP" && python3 /run/extract.py -i "$PAT" -d 2>/run/extract.log); rc=$?; } || :
if [ "$ARCH" == "amd64" ]; then if (( rc != 0 )); then
{ /run/extract/syno_extract_system_patch "$PAT" "$TMP/."; rc=$?; } || : cat /run/extract.log
else error "Failed to extract PAT file, reason $rc" && exit 63
{ qemu-x86_64 /run/extract/syno_extract_system_patch "$PAT" "$TMP/."; rc=$?; } || :
fi fi
export LD_LIBRARY_PATH=""
(( rc != 0 )) && error "Failed to extract PAT file, reason $rc" && exit 63
fi fi
rm -rf /run/extract
MSG="Preparing system partition..." MSG="Preparing system partition..."
info "Install: $MSG" && html "$MSG" info "Install: $MSG" && html "$MSG"
@@ -368,12 +272,9 @@ mv "$HDA.tgz" "$HDA.txz"
[ -d "$PKG" ] && mv "$PKG/" "$MOUNT/.SynoUpgradePackages/" [ -d "$PKG" ] && mv "$PKG/" "$MOUNT/.SynoUpgradePackages/"
rm -f "$MOUNT/.SynoUpgradePackages/ActiveInsight-"* rm -f "$MOUNT/.SynoUpgradePackages/ActiveInsight-"*
[ -s "$HDP.txz" ] && tar xpfJ "$HDP.txz" --absolute-names -C "$MOUNT/"
if [ -s "$IDB.txz" ]; then if [ -s "$IDB.txz" ]; then
INDEX_DB="$MOUNT/usr/syno/synoman/indexdb/" INDEX_DB="$MOUNT/usr/syno/synoman/indexdb"
mkdir -p "$INDEX_DB" mkdir -p "$INDEX_DB"
tar xpfJ "$IDB.txz" --absolute-names -C "$INDEX_DB"
fi fi
LABEL="1.44.1-42218" LABEL="1.44.1-42218"
@@ -381,22 +282,12 @@ OFFSET="1048576" # 2048 * 512
NUMBLOCKS="2097152" # (16777216 * 512) / 4096 NUMBLOCKS="2097152" # (16777216 * 512) / 4096
MSG="Installing system partition..." MSG="Installing system partition..."
if [[ "$ROOT" != [Nn]* ]]; then fakeroot -- bash -c "set -Eeu;\
[ -s $HDP.txz ] && tar xpfJ $HDP.txz --absolute-names -C $MOUNT/;\
tar xpfJ "$HDA.txz" --absolute-names --skip-old-files -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/;\
info "Install: $MSG" && html "$MSG" 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"
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" rm -rf "$MOUNT"
echo "$BASE" > "$STORAGE/dsm.ver" echo "$BASE" > "$STORAGE/dsm.ver"

View File

@@ -29,6 +29,8 @@ ADD_ERR="Please add the following setting to your container:"
configureDHCP() { configureDHCP() {
[[ "$DEBUG" == [Yy1]* ]] && echo "Configuring MACVTAP networking..."
# Create the necessary file structure for /dev/vhost-net # Create the necessary file structure for /dev/vhost-net
if [ ! -c /dev/vhost-net ]; then if [ ! -c /dev/vhost-net ]; then
if mknod /dev/vhost-net c 10 238; then if mknod /dev/vhost-net c 10 238; then
@@ -59,14 +61,15 @@ configureDHCP() {
fi ;; fi ;;
esac esac
if [[ "$MTU" != "0" ]] && [[ "$MTU" != "1500" ]]; then if [[ "$MTU" != "0" && "$MTU" != "1500" ]]; then
if ! ip link set dev "$VM_NET_TAP" mtu "$MTU"; then if ! ip link set dev "$VM_NET_TAP" mtu "$MTU"; then
warn "Failed to set MTU size.." warn "Failed to set MTU size to $MTU." && MTU="0"
fi fi
fi fi
while ! ip link set "$VM_NET_TAP" up; do while ! ip link set "$VM_NET_TAP" up; do
info "Waiting for MAC address $VM_NET_MAC to become available..." info "Waiting for MAC address $VM_NET_MAC to become available..."
info "If you cloned this machine, please delete the 'dsm.mac' file to generate a different MAC address."
sleep 2 sleep 2
done done
@@ -78,7 +81,7 @@ configureDHCP() {
IFS=: read -r MAJOR MINOR < <(cat /sys/devices/virtual/net/"$VM_NET_TAP"/tap*/dev) IFS=: read -r MAJOR MINOR < <(cat /sys/devices/virtual/net/"$VM_NET_TAP"/tap*/dev)
(( MAJOR < 1)) && error "Cannot find: sys/devices/virtual/net/$VM_NET_TAP" && return 1 (( MAJOR < 1)) && error "Cannot find: sys/devices/virtual/net/$VM_NET_TAP" && return 1
[[ ! -e "$TAP_PATH" ]] && [[ -e "/dev0/${TAP_PATH##*/}" ]] && ln -s "/dev0/${TAP_PATH##*/}" "$TAP_PATH" [[ ! -e "$TAP_PATH" && -e "/dev0/${TAP_PATH##*/}" ]] && ln -s "/dev0/${TAP_PATH##*/}" "$TAP_PATH"
if [[ ! -e "$TAP_PATH" ]]; then if [[ ! -e "$TAP_PATH" ]]; then
{ mknod "$TAP_PATH" c "$MAJOR" "$MINOR" ; rc=$?; } || : { mknod "$TAP_PATH" c "$MAJOR" "$MINOR" ; rc=$?; } || :
@@ -104,29 +107,42 @@ configureDHCP() {
configureDNS() { configureDNS() {
# dnsmasq configuration: local log="/var/log/dnsmasq.log"
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" rm -f "$log"
# Create lease file for faster resolve # 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 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 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 # Set DNS server and gateway
DNSMASQ_OPTS+=" --dhcp-option=option:dns-server,${VM_NET_IP%.*}.1 --dhcp-option=option:router,${VM_NET_IP%.*}.1" 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"
# Add DNS entry for container # Add DNS entry for container
DNSMASQ_OPTS+=" --address=/host.lan/${VM_NET_IP%.*}.1" DNSMASQ_OPTS+=" --address=/host.lan/${VM_NET_IP%.*}.1"
DNSMASQ_OPTS+=" --log-facility=$log"
DNSMASQ_OPTS=$(echo "$DNSMASQ_OPTS" | sed 's/\t/ /g' | tr -s ' ' | sed 's/^ *//') DNSMASQ_OPTS=$(echo "$DNSMASQ_OPTS" | sed 's/\t/ /g' | tr -s ' ' | sed 's/^ *//')
if [[ "${DEBUG_DNS:-}" == [Yy1]* ]]; then [[ "$DEBUG" == [Yy1]* ]] && echo "Starting Dnsmasq daemon..."
DNSMASQ_OPTS+=" -d"
$DNSMASQ ${DNSMASQ_OPTS:+ $DNSMASQ_OPTS} &
return 0
fi
if ! $DNSMASQ ${DNSMASQ_OPTS:+ $DNSMASQ_OPTS}; then if ! $DNSMASQ ${DNSMASQ_OPTS:+ $DNSMASQ_OPTS}; then
error "Failed to start dnsmasq, reason: $?" && return 1 local msg="Failed to start Dnsmasq, reason: $?"
[ -f "$log" ] && cat "$log"
error "$msg"
return 1
fi
if [[ "${DEBUG_DNS:-}" == [Yy1]* ]]; then
tail -fn +0 "$log" &
fi fi
return 0 return 0
@@ -146,7 +162,18 @@ getUserPorts() {
list="${list%% }" list="${list%% }"
for port in $list; do for port in $list; do
args+="hostfwd=tcp::$port-$VM_NET_IP:$port," proto="tcp"
num="$port"
if [[ "$port" == */udp ]]; then
proto="udp"
num="${port%/udp}"
elif [[ "$port" == */tcp ]]; then
proto="tcp"
num="${port%/tcp}"
fi
args+="hostfwd=$proto::$num-$VM_NET_IP:$num,"
done done
echo "${args%?}" echo "${args%?}"
@@ -155,8 +182,9 @@ getUserPorts() {
getHostPorts() { getHostPorts() {
local list=$1 local list="$1"
[ -z "$list" ] && list="$MON_PORT" || list+=",$MON_PORT"
[ -z "$list" ] && echo "" && return 0 [ -z "$list" ] && echo "" && return 0
if [[ "$list" != *","* ]]; then if [[ "$list" != *","* ]]; then
@@ -170,7 +198,13 @@ getHostPorts() {
configureUser() { 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" [[ "$DEBUG" == [Yy1]* ]] && echo "Configuring SLIRP networking..."
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
local forward local forward
forward=$(getUserPorts "$USER_PORTS") forward=$(getUserPorts "$USER_PORTS")
@@ -184,8 +218,11 @@ configureNAT() {
local tuntap="TUN device is missing. $ADD_ERR --device /dev/net/tun" 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" local tables="The 'ip_tables' kernel module is not loaded. Try this command: sudo modprobe ip_tables iptable_nat"
[[ "$DEBUG" == [Yy1]* ]] && echo "Configuring NAT networking..."
# Create the necessary file structure for /dev/net/tun # Create the necessary file structure for /dev/net/tun
if [ ! -c /dev/net/tun ]; then if [ ! -c /dev/net/tun ]; then
[[ "$PODMAN" == [Yy1]* ]] && return 1
[ ! -d /dev/net ] && mkdir -m 755 /dev/net [ ! -d /dev/net ] && mkdir -m 755 /dev/net
if mknod /dev/net/tun c 10 200; then if mknod /dev/net/tun c 10 200; then
chmod 666 /dev/net/tun chmod 666 /dev/net/tun
@@ -198,9 +235,11 @@ configureNAT() {
# Check port forwarding flag # Check port forwarding flag
if [[ $(< /proc/sys/net/ipv4/ip_forward) -eq 0 ]]; then if [[ $(< /proc/sys/net/ipv4/ip_forward) -eq 0 ]]; then
{ sysctl -w net.ipv4.ip_forward=1 > /dev/null; rc=$?; } || : { sysctl -w net.ipv4.ip_forward=1 > /dev/null 2>&1; rc=$?; } || :
if (( rc != 0 )) || [[ $(< /proc/sys/net/ipv4/ip_forward) -eq 0 ]]; then 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 [[ "$PODMAN" == [Yy1]* ]] && return 1
error "IP forwarding is disabled. $ADD_ERR --sysctl net.ipv4.ip_forward=1"
return 1
fi fi
fi fi
@@ -225,9 +264,9 @@ configureNAT() {
error "$tuntap" && return 1 error "$tuntap" && return 1
fi fi
if [[ "$MTU" != "0" ]] && [[ "$MTU" != "1500" ]]; then if [[ "$MTU" != "0" && "$MTU" != "1500" ]]; then
if ! ip link set dev "$VM_NET_TAP" mtu "$MTU"; then if ! ip link set dev "$VM_NET_TAP" mtu "$MTU"; then
warn "Failed to set MTU size.." warn "Failed to set MTU size to $MTU." && MTU="0"
fi fi
fi fi
@@ -302,7 +341,7 @@ closeBridge() {
closeNetwork() { closeNetwork() {
if [[ "$DHCP" == [Yy1]* ]]; then if [[ "${WEB:-}" != [Nn]* && "$DHCP" == [Yy1]* ]]; then
# Shutdown nginx # Shutdown nginx
nginx -s stop 2> /dev/null nginx -s stop 2> /dev/null
@@ -330,17 +369,17 @@ closeNetwork() {
checkOS() { checkOS() {
local name local kernel
local os="" local os=""
local if="macvlan" local if="macvlan"
name=$(uname -a) kernel=$(uname -a)
[[ "${name,,}" == *"darwin"* ]] && os="Docker Desktop for macOS" [[ "${kernel,,}" == *"darwin"* ]] && os="Docker Desktop for macOS"
[[ "${name,,}" == *"microsoft"* ]] && os="Docker Desktop for Windows" [[ "${kernel,,}" == *"microsoft"* ]] && os="Docker Desktop for Windows"
if [[ "$DHCP" == [Yy1]* ]]; then if [[ "$DHCP" == [Yy1]* ]]; then
if="macvtap" if="macvtap"
[[ "${name,,}" == *"synology"* ]] && os="Synology Container Manager" [[ "${kernel,,}" == *"synology"* ]] && os="Synology Container Manager"
fi fi
if [ -n "$os" ]; then if [ -n "$os" ]; then
@@ -365,19 +404,46 @@ getInfo() {
if [ ! -d "/sys/class/net/$VM_NET_DEV" ]; then if [ ! -d "/sys/class/net/$VM_NET_DEV" ]; then
error "Network interface '$VM_NET_DEV' does not exist inside the container!" 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 27 error "$ADD_ERR -e \"VM_NET_DEV=NAME\" to specify another interface name." && exit 26
fi
local result nic bus
result=$(ethtool -i "$VM_NET_DEV")
nic=$(grep -m 1 -i 'driver:' <<< "$result" | awk '{print $(2)}')
bus=$(grep -m 1 -i 'bus-info:' <<< "$result" | awk '{print $(2)}')
if [[ "${bus,,}" != "" && "${bus,,}" != "n/a" && "${bus,,}" != "tap" ]]; then [[ "$DEBUG" == [Yy1]* ]] && info "Detected BUS: $bus"
error "This container does not support host mode networking!"
exit 29
fi
if [[ "$DHCP" == [Yy1]* ]]; then
if [[ "${nic,,}" == "ipvlan" ]]; then
error "This container does not support IPVLAN networking when DHCP=Y."
exit 29
fi
if [[ "${nic,,}" != "macvlan" ]]; then
[[ "$DEBUG" == [Yy1]* ]] && info "Detected NIC: $nic"
error "The container needs to be in a MACVLAN network when DHCP=Y."
exit 29
fi
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 fi
if [ -z "$MTU" ]; then if [ -z "$MTU" ]; then
MTU=$(cat "/sys/class/net/$VM_NET_DEV/mtu") MTU=$(cat "/sys/class/net/$VM_NET_DEV/mtu")
fi fi
if [ "$MTU" -gt "1500" ]; then
info "MTU size is too large: $MTU, ignoring..." && MTU="0"
fi
if [[ "${ADAPTER,,}" != "virtio-net-pci" ]]; then if [[ "${ADAPTER,,}" != "virtio-net-pci" ]]; then
if [[ "$MTU" != "0" ]] && [[ "$MTU" != "1500" ]]; then if [[ "$MTU" != "0" && "$MTU" != "1500" ]]; then
warn "MTU size is $MTU, but cannot be set for $ADAPTER adapters!" && MTU="0" warn "MTU size is $MTU, but cannot be set for $ADAPTER adapters!" && MTU="0"
fi fi
fi fi
@@ -385,6 +451,7 @@ getInfo() {
if [ -z "$VM_NET_MAC" ]; then if [ -z "$VM_NET_MAC" ]; then
local file="$STORAGE/dsm.mac" local file="$STORAGE/dsm.mac"
[ -s "$file" ] && VM_NET_MAC=$(<"$file") [ -s "$file" ] && VM_NET_MAC=$(<"$file")
VM_NET_MAC="${VM_NET_MAC//[![:print:]]/}"
if [ -z "$VM_NET_MAC" ]; then if [ -z "$VM_NET_MAC" ]; then
# Generate MAC address based on Docker container ID in hostname # Generate MAC address based on Docker container ID in hostname
VM_NET_MAC=$(echo "$HOST" | md5sum | sed 's/^\(..\)\(..\)\(..\)\(..\)\(..\).*$/02:11:32:\3:\4:\5/') VM_NET_MAC=$(echo "$HOST" | md5sum | sed 's/^\(..\)\(..\)\(..\)\(..\)\(..\).*$/02:11:32:\3:\4:\5/')
@@ -414,6 +481,7 @@ getInfo() {
[ -n "$IP6" ] && IP6=$(echo "$IP6" | sed -e's/^.*inet6 \([^ ]*\)\/.*$/\1/;t;d' | head -n 1) [ -n "$IP6" ] && IP6=$(echo "$IP6" | sed -e's/^.*inet6 \([^ ]*\)\/.*$/\1/;t;d' | head -n 1)
fi fi
[ -f "/run/.containerenv" ] && PODMAN="Y" || PODMAN="N"
echo "$IP" > /run/shm/qemu.ip echo "$IP" > /run/shm/qemu.ip
return 0 return 0
@@ -428,15 +496,20 @@ if [[ "$NETWORK" == [Nn]* ]]; then
return 0 return 0
fi fi
[[ "$DEBUG" == [Yy1]* ]] && echo "Retrieving network information..."
getInfo getInfo
html "Initializing network..." html "Initializing network..."
if [[ "$DEBUG" == [Yy1]* ]]; then if [[ "$DEBUG" == [Yy1]* ]]; then
mtu=$(cat "/sys/class/net/$VM_NET_DEV/mtu") 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" line="Host: $HOST IP: $IP Gateway: $GATEWAY Interface: $VM_NET_DEV MAC: $VM_NET_MAC MTU: $mtu"
[[ "$MTU" != "0" ]] && [[ "$MTU" != "$mtu" ]] && line+=" ($MTU)" [[ "$MTU" != "0" && "$MTU" != "$mtu" ]] && line+=" ($MTU)"
info "$line" info "$line"
[ -f /etc/resolv.conf ] && grep '^nameserver*' /etc/resolv.conf 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 echo
fi fi
@@ -444,6 +517,9 @@ if [[ "$IP" == "172.17."* ]]; then
warn "your container IP starts with 172.17.* which will cause conflicts when you install the Container Manager package inside DSM!" warn "your container IP starts with 172.17.* which will cause conflicts when you install the Container Manager package inside DSM!"
fi fi
# Clean up old files
rm -f /var/run/dnsmasq.pid
if [[ -d "/sys/class/net/$VM_NET_TAP" ]]; then if [[ -d "/sys/class/net/$VM_NET_TAP" ]]; then
info "Lingering interface will be removed..." info "Lingering interface will be removed..."
ip link delete "$VM_NET_TAP" || true ip link delete "$VM_NET_TAP" || true
@@ -453,10 +529,6 @@ if [[ "$DHCP" == [Yy1]* ]]; then
checkOS 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 # Configure for macvtap interface
configureDHCP || exit 20 configureDHCP || exit 20
@@ -465,13 +537,17 @@ if [[ "$DHCP" == [Yy1]* ]]; then
else else
if [[ "$IP" != "172."* ]] && [[ "$IP" != "10.8"* ]] && [[ "$IP" != "10.9"* ]]; then if [[ "$IP" != "172."* && "$IP" != "10.8"* && "$IP" != "10.9"* ]]; then
checkOS checkOS
fi fi
# Shutdown nginx if [[ "${WEB:-}" != [Nn]* ]]; then
nginx -s stop 2> /dev/null
fWait "nginx" # Shutdown nginx
nginx -s stop 2> /dev/null
fWait "nginx"
fi
if [[ "${NETWORK,,}" != "user"* ]]; then if [[ "${NETWORK,,}" != "user"* ]]; then
@@ -480,7 +556,14 @@ else
closeBridge closeBridge
NETWORK="user" NETWORK="user"
warn "falling back to user-mode networking! Performance will be bad and port mapping will not work." 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: when you want to expose ports in this mode, map them using this variable: \"USER_PORTS=5000,5001\"."
fi fi
@@ -496,6 +579,6 @@ else
fi fi
NET_OPTS+=" -device $ADAPTER,id=net0,netdev=hostnet0,romfile=,mac=$VM_NET_MAC" NET_OPTS+=" -device $ADAPTER,id=net0,netdev=hostnet0,romfile=,mac=$VM_NET_MAC"
[[ "$MTU" != "0" ]] && [[ "$MTU" != "1500" ]] && NET_OPTS+=",host_mtu=$MTU" [[ "$MTU" != "0" && "$MTU" != "1500" ]] && NET_OPTS+=",host_mtu=$MTU"
return 0 return 0

View File

@@ -1,15 +1,15 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -Eeuo pipefail set -Eeuo pipefail
: "${API_TIMEOUT:="50"}" # API Call timeout
: "${QEMU_TIMEOUT:="50"}" # QEMU Termination timeout
# Configure QEMU for graceful shutdown # Configure QEMU for graceful shutdown
API_CMD=6 API_CMD=6
API_TIMEOUT=50
API_HOST="127.0.0.1:2210" API_HOST="127.0.0.1:2210"
QEMU_TERM="" QEMU_TERM=""
QEMU_PORT=7100
QEMU_TIMEOUT=50
QEMU_DIR="/run/shm" QEMU_DIR="/run/shm"
QEMU_PID="$QEMU_DIR/qemu.pid" QEMU_PID="$QEMU_DIR/qemu.pid"
QEMU_LOG="$QEMU_DIR/qemu.log" QEMU_LOG="$QEMU_DIR/qemu.log"
@@ -83,7 +83,7 @@ terminal() {
fi fi
if [ ! -c "$dev" ]; then if [ ! -c "$dev" ]; then
dev=$(echo 'info chardev' | nc -q 1 -w 1 localhost "$QEMU_PORT" | tr -d '\000') dev=$(echo 'info chardev' | nc -q 1 -w 1 localhost "$MON_PORT" | tr -d '\000')
dev="${dev#*serial0}" dev="${dev#*serial0}"
dev="${dev#*pty:}" dev="${dev#*pty:}"
dev="${dev%%$'\n'*}" dev="${dev%%$'\n'*}"
@@ -127,7 +127,7 @@ _graceful_shutdown() {
fi fi
# Don't send the powerdown signal because vDSM ignores ACPI signals # Don't send the powerdown signal because vDSM ignores ACPI signals
# echo 'system_powerdown' | nc -q 1 -w 1 localhost "${QEMU_PORT}" > /dev/null # echo 'system_powerdown' | nc -q 1 -w 1 localhost "$MON_PORT" > /dev/null
# Send shutdown command to guest agent via serial port # Send shutdown command to guest agent via serial port
url="http://$API_HOST/read?command=$API_CMD&timeout=$API_TIMEOUT" url="http://$API_HOST/read?command=$API_CMD&timeout=$API_TIMEOUT"
@@ -172,7 +172,7 @@ _graceful_shutdown() {
MON_OPTS="\ MON_OPTS="\
-pidfile $QEMU_PID \ -pidfile $QEMU_PID \
-name $PROCESS,process=$PROCESS,debug-threads=on \ -name $PROCESS,process=$PROCESS,debug-threads=on \
-monitor telnet:localhost:$QEMU_PORT,server,nowait,nodelay" -monitor telnet:localhost:$MON_PORT,server,nowait,nodelay"
if [[ "$CONSOLE" != [Yy]* ]]; then if [[ "$CONSOLE" != [Yy]* ]]; then

View File

@@ -7,28 +7,32 @@ set -Eeuo pipefail
: "${HOST_CPU:=""}" : "${HOST_CPU:=""}"
: "${CPU_FLAGS:=""}" : "${CPU_FLAGS:=""}"
: "${CPU_MODEL:=""}" : "${CPU_MODEL:=""}"
: "${DEF_MODEL:="qemu64"}"
CLOCKSOURCE="tsc" CLOCKSOURCE="tsc"
[[ "${ARCH,,}" == "arm64" ]] && CLOCKSOURCE="arch_sys_counter" [[ "${ARCH,,}" == "arm64" ]] && CLOCKSOURCE="arch_sys_counter"
CLOCK="/sys/devices/system/clocksource/clocksource0/current_clocksource" CLOCK="/sys/devices/system/clocksource/clocksource0/current_clocksource"
if [ ! -f "$CLOCK" ]; then if [ ! -f "$CLOCK" ]; then
warn "file \"$CLOCK\" cannot not found?" warn "file \"$CLOCK\" cannot not found?"
else else
result=$(<"$CLOCK") result=$(<"$CLOCK")
result="${result//[![:print:]]/}"
case "${result,,}" in case "${result,,}" in
"${CLOCKSOURCE,,}" ) ;; "${CLOCKSOURCE,,}" ) ;;
"kvm-clock" ) info "Nested KVM virtualization detected.." ;; "kvm-clock" ) info "Nested KVM virtualization detected.." ;;
"hyperv_clocksource_tsc_page" ) info "Nested Hyper-V 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'" ;; "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'" ;; *) warn "unexpected clock source detected: '$result'. Please set host clock source to '$CLOCKSOURCE'." ;;
esac esac
fi fi
if [[ "${ARCH,,}" != "amd64" ]]; then if [[ "$KVM" == [Nn]* ]]; then
KVM="N" warn "KVM acceleration is disabled, this will cause the machine to run about 10 times slower!"
warn "your CPU architecture is ${ARCH^^} and cannot provide KVM acceleration for x64 instructions, this will cause a major loss of performance." else
if [[ "${ARCH,,}" != "amd64" ]]; then
KVM="N"
warn "your CPU architecture is ${ARCH^^} and cannot provide KVM acceleration for x64 instructions, so the machine will run about 10 times slower."
fi
fi fi
if [[ "$KVM" != [Nn]* ]]; then if [[ "$KVM" != [Nn]* ]]; then
@@ -36,14 +40,14 @@ if [[ "$KVM" != [Nn]* ]]; then
KVM_ERR="" KVM_ERR=""
if [ ! -e /dev/kvm ]; then if [ ! -e /dev/kvm ]; then
KVM_ERR="(device file missing)" KVM_ERR="(/dev/kvm is missing)"
else else
if ! sh -c 'echo -n > /dev/kvm' &> /dev/null; then if ! sh -c 'echo -n > /dev/kvm' &> /dev/null; then
KVM_ERR="(no write access)" KVM_ERR="(/dev/kvm is unwriteable)"
else else
flags=$(sed -ne '/^flags/s/^.*: //p' /proc/cpuinfo) flags=$(sed -ne '/^flags/s/^.*: //p' /proc/cpuinfo)
if ! grep -qw "vmx\|svm" <<< "$flags"; then if ! grep -qw "vmx\|svm" <<< "$flags"; then
KVM_ERR="(vmx/svm disabled)" KVM_ERR="(not enabled in BIOS)"
fi fi
fi fi
fi fi
@@ -51,10 +55,18 @@ if [[ "$KVM" != [Nn]* ]]; then
if [ -n "$KVM_ERR" ]; then if [ -n "$KVM_ERR" ]; then
KVM="N" KVM="N"
if [[ "$OSTYPE" =~ ^darwin ]]; then if [[ "$OSTYPE" =~ ^darwin ]]; then
warn "you are using macOS which has no KVM support, this will cause a major loss of performance." warn "you are using macOS which has no KVM support, so the machine will run about 10 times slower."
else else
error "KVM acceleration not available $KVM_ERR, this will cause a major loss of performance." kernel=$(uname -a)
error "See the FAQ on how to diagnose the cause, or continue without KVM by setting KVM=N (not recommended)." 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 the machine to run about 10 times slower."
error "See the FAQ for possible causes, or disable acceleration by adding the \"KVM=N\" variable (not recommended)." ;;
esac
[[ "$DEBUG" != [Yy1]* ]] && exit 88 [[ "$DEBUG" != [Yy1]* ]] && exit 88
fi fi
fi fi
@@ -68,7 +80,7 @@ if [[ "$KVM" != [Nn]* ]]; then
if ! grep -qw "sse4_2" <<< "$flags"; then if ! grep -qw "sse4_2" <<< "$flags"; then
info "Your CPU does not have the SSE4 instruction set that Virtual DSM requires, it will be emulated..." info "Your CPU does not have the SSE4 instruction set that Virtual DSM requires, it will be emulated..."
[ -z "$CPU_MODEL" ] && CPU_MODEL="$DEF_MODEL" [ -z "$CPU_MODEL" ] && CPU_MODEL="qemu64"
CPU_FEATURES+=",+ssse3,+sse4.1,+sse4.2" CPU_FEATURES+=",+ssse3,+sse4.1,+sse4.2"
fi fi
@@ -111,7 +123,7 @@ else
CPU_MODEL="max" CPU_MODEL="max"
CPU_FEATURES+=",migratable=no" CPU_FEATURES+=",migratable=no"
else else
CPU_MODEL="$DEF_MODEL" CPU_MODEL="qemu64"
fi fi
fi fi
@@ -119,6 +131,30 @@ else
fi fi
if [[ "$ARGUMENTS" == *"-cpu host,"* ]]; then
args="${ARGUMENTS} "
prefix="${args/-cpu host,*/}"
suffix="${args/*-cpu host,/}"
param="${suffix%% *}"
suffix="${suffix#* }"
args="${prefix}${suffix}"
ARGUMENTS="${args::-1}"
if [ -z "$CPU_FLAGS" ]; then
CPU_FLAGS="$param"
else
CPU_FLAGS+=",$param"
fi
else
if [[ "$ARGUMENTS" == *"-cpu host"* ]]; then
ARGUMENTS="${ARGUMENTS//-cpu host/}"
fi
fi
if [ -z "$CPU_FLAGS" ]; then if [ -z "$CPU_FLAGS" ]; then
if [ -z "$CPU_FEATURES" ]; then if [ -z "$CPU_FEATURES" ]; then
CPU_FLAGS="$CPU_MODEL" CPU_FLAGS="$CPU_MODEL"

View File

@@ -26,7 +26,7 @@ do
bytes=$(du -sb "$file" | cut -f1) bytes=$(du -sb "$file" | cut -f1)
if (( bytes > 1000 )); then if (( bytes > 1000 )); then
if [ -z "$total" ] || [[ "$total" == "0" ]]; 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 else
size="$(echo "$bytes" "$total" | awk '{printf "%.1f", $1 * 100 / $2}')" size="$(echo "$bytes" "$total" | awk '{printf "%.1f", $1 * 100 / $2}')"
size="$size%" size="$size%"

View File

@@ -1,11 +1,8 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -Eeuo pipefail 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 trap 'error "Status $? while: $BASH_COMMAND (line $LINENO/$BASH_LINENO)"' ERR
[[ "${TRACE:-}" == [Yy1]* ]] && set -o functrace && trap 'echo "# $BASH_COMMAND" >&2' DEBUG
[ ! -f "/run/entry.sh" ] && error "Script must run inside Docker container!" && exit 11 [ ! -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 [ "$(id -u)" -ne "0" ] && error "Script must be executed with root privileges." && exit 12
@@ -21,8 +18,8 @@ echo " For support visit $SUPPORT"
: "${CONSOLE:="N"}" # Disable console mode : "${CONSOLE:="N"}" # Disable console mode
: "${ALLOCATE:=""}" # Preallocate diskspace : "${ALLOCATE:=""}" # Preallocate diskspace
: "${ARGUMENTS:=""}" # Extra QEMU parameters : "${ARGUMENTS:=""}" # Extra QEMU parameters
: "${CPU_CORES:="1"}" # Amount of CPU cores : "${CPU_CORES:="2"}" # Amount of CPU cores
: "${RAM_SIZE:="1G"}" # Maximum RAM amount : "${RAM_SIZE:="2G"}" # Maximum RAM amount
: "${RAM_CHECK:="Y"}" # Check available RAM : "${RAM_CHECK:="Y"}" # Check available RAM
: "${DISK_SIZE:="16G"}" # Initial data disk size : "${DISK_SIZE:="16G"}" # Initial data disk size
: "${STORAGE:="/storage"}" # Storage folder location : "${STORAGE:="/storage"}" # Storage folder location
@@ -38,7 +35,7 @@ TEMPLATE="/var/www/index.html"
FOOTER1="$APP for Docker v$(</run/version)" FOOTER1="$APP for Docker v$(</run/version)"
FOOTER2="<a href='$SUPPORT'>$SUPPORT</a>" FOOTER2="<a href='$SUPPORT'>$SUPPORT</a>"
CPI=$(lscpu) CPU=$(cpu)
SYS=$(uname -r) SYS=$(uname -r)
HOST=$(hostname -s) HOST=$(hostname -s)
KERNEL=$(echo "$SYS" | cut -b 1) KERNEL=$(echo "$SYS" | cut -b 1)
@@ -46,43 +43,21 @@ MINOR=$(echo "$SYS" | cut -d '.' -f2)
ARCH=$(dpkg --print-architecture) ARCH=$(dpkg --print-architecture)
CORES=$(grep -c '^processor' /proc/cpuinfo) CORES=$(grep -c '^processor' /proc/cpuinfo)
if ! grep -qi "socket(s)" <<< "$CPI"; then if ! grep -qi "socket(s)" <<< "$(lscpu)"; then
SOCKETS=1 SOCKETS=1
else else
SOCKETS=$(echo "$CPI" | grep -m 1 -i 'socket(s)' | awk '{print $(2)}') SOCKETS=$(lscpu | grep -m 1 -i 'socket(s)' | awk '{print $(2)}')
fi fi
if ! grep -qi "model name" <<< "$CPI"; then CPU_CORES="${CPU_CORES// /}"
CPU="" [[ "${CPU_CORES,,}" == "max" ]] && CPU_CORES="$CORES"
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 [ -n "${CPU_CORES//[0-9 ]}" ] && error "Invalid amount of CPU_CORES: $CPU_CORES" && exit 15
if [ "$CPU_CORES" -gt "$CORES" ]; then
warn "The amount for CPU_CORES (${CPU_CORES}) exceeds the amount of physical cores, so will be limited to ${CORES}."
CPU_CORES="$CORES"
fi
# Check system # Check system
if [ ! -d "/dev/shm" ]; then if [ ! -d "/dev/shm" ]; then
@@ -102,38 +77,18 @@ if [ ! -d "$STORAGE" ]; then
error "Storage folder ($STORAGE) not found!" && exit 13 error "Storage folder ($STORAGE) not found!" && exit 13
fi fi
if [ ! -w "$STORAGE" ]; then
error "Storage folder ($STORAGE) is not writeable!" && exit 13
fi
# Check filesystem # Check filesystem
FS=$(stat -f -c %T "$STORAGE") FS=$(stat -f -c %T "$STORAGE")
if [[ "${FS,,}" == "ecryptfs" ]] || [[ "${FS,,}" == "tmpfs" ]]; then if [[ "${FS,,}" == "ecryptfs" || "${FS,,}" == "tmpfs" ]]; then
DISK_IO="threads" DISK_IO="threads"
DISK_CACHE="writeback" DISK_CACHE="writeback"
fi 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 # Read memory
RAM_SPARE=500000000 RAM_SPARE=500000000
RAM_AVAIL=$(free -b | grep -m 1 Mem: | awk '{print $7}') RAM_AVAIL=$(free -b | grep -m 1 Mem: | awk '{print $7}')
@@ -142,6 +97,12 @@ RAM_TOTAL=$(free -b | grep -m 1 Mem: | awk '{print $2}')
RAM_SIZE="${RAM_SIZE// /}" RAM_SIZE="${RAM_SIZE// /}"
[ -z "$RAM_SIZE" ] && error "RAM_SIZE not specified!" && exit 16 [ -z "$RAM_SIZE" ] && error "RAM_SIZE not specified!" && exit 16
if [[ "${RAM_SIZE,,}" == "max" ]]; then
RAM_WANTED=$(( RAM_AVAIL - RAM_SPARE - RAM_SPARE ))
RAM_WANTED=$(( RAM_WANTED / 1073741825 ))
RAM_SIZE="${RAM_WANTED}G"
fi
if [ -z "${RAM_SIZE//[0-9. ]}" ]; then if [ -z "${RAM_SIZE//[0-9. ]}" ]; then
[ "${RAM_SIZE%%.*}" -lt "130" ] && RAM_SIZE="${RAM_SIZE}G" || RAM_SIZE="${RAM_SIZE}M" [ "${RAM_SIZE%%.*}" -lt "130" ] && RAM_SIZE="${RAM_SIZE}G" || RAM_SIZE="${RAM_SIZE}M"
fi fi
@@ -181,91 +142,6 @@ rm -f /run/shm/dsm.url
rm -rf /tmp/dsm rm -rf /tmp/dsm
rm -rf "$STORAGE/tmp" 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() { getCountry() {
local url=$1 local url=$1
local query=$2 local query=$2
@@ -298,6 +174,7 @@ setCountry() {
[ -z "$COUNTRY" ] && getCountry "https://ifconfig.co/json" ".country_iso" [ -z "$COUNTRY" ] && getCountry "https://ifconfig.co/json" ".country_iso"
[ -z "$COUNTRY" ] && getCountry "https://api.ip2location.io" ".country_code" [ -z "$COUNTRY" ] && getCountry "https://api.ip2location.io" ".country_code"
[ -z "$COUNTRY" ] && getCountry "https://ipinfo.io/json" ".country" [ -z "$COUNTRY" ] && getCountry "https://ipinfo.io/json" ".country"
[ -z "$COUNTRY" ] && getCountry "https://api.ipquery.io/?format=json" ".location.country_code"
[ -z "$COUNTRY" ] && getCountry "https://api.myip.com" ".cc" [ -z "$COUNTRY" ] && getCountry "https://api.myip.com" ".cc"
return 0 return 0
@@ -326,20 +203,29 @@ addPackage() {
return 0 return 0
} }
# shellcheck disable=SC2143 : "${MON_PORT:="7100"}" # Monitor port
if [ -f /proc/net/if_inet6 ] && [ -n "$(ifconfig -a | grep inet6)" ]; then : "${WEB_PORT:="5000"}" # Webserver port
sed -i "s/listen 5000 default_server;/listen [::]:5000 default_server ipv6only=off;/g" /etc/nginx/sites-enabled/web.conf cp -r /var/www/* /run/shm
html "Starting $APP for Docker..."
else if [[ "${WEB:-}" != [Nn]* ]]; then
sed -i "s/listen [::]:5000 default_server ipv6only=off;/listen 5000 default_server;/g" /etc/nginx/sites-enabled/web.conf mkdir -p /etc/nginx/sites-enabled
cp /etc/nginx/default.conf /etc/nginx/sites-enabled/web.conf
sed -i "s/listen 5000 default_server;/listen $WEB_PORT default_server;/g" /etc/nginx/sites-enabled/web.conf
# shellcheck disable=SC2143
if [ -f /proc/net/if_inet6 ] && [ -n "$(ifconfig -a | grep inet6)" ]; then
sed -i "s/listen $WEB_PORT default_server;/listen [::]:$WEB_PORT default_server ipv6only=off;/g" /etc/nginx/sites-enabled/web.conf
fi
# Start webserver
nginx -e stderr
fi fi
# Start webserver
cp -r /var/www/* /run/shm
html "Starting $APP for Docker..."
nginx -e stderr
return 0 return 0

4
src/start.sh Normal file
View File

@@ -0,0 +1,4 @@
#!/usr/bin/env bash
set -Eeuo pipefail
# Override this placeholder file using a Docker bind to execute a script during startup!

162
src/utils.sh Normal file
View File

@@ -0,0 +1,162 @@
#!/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// [0-9] Core}"
cpu="${cpu// [0-9][0-9] Core}"
cpu="${cpu// [0-9][0-9][0-9] Core}"
cpu="${cpu//[0-9]th Gen }"
cpu="${cpu//[0-9][0-9]th Gen }"
cpu="${cpu// Processor/}"
cpu="${cpu// Quad core/}"
cpu="${cpu// Dual core/}"
cpu="${cpu// Octa core/}"
cpu="${cpu// Hexa core/}"
cpu="${cpu// Core TM/ Core}"
cpu="${cpu// with Radeon Graphics/}"
cpu="${cpu// with Radeon Vega Graphics/}"
cpu="${cpu// with Radeon Vega Mobile Gfx/}"
cpu="${cpu// w Radeon [0-9][0-9][0-9]M 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