mirror of
https://github.com/vdsm/virtual-dsm.git
synced 2025-11-06 18:13:43 +08:00
Compare commits
62 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2c7cea042f | ||
|
|
fc92b66ff4 | ||
|
|
89ae24a2ac | ||
|
|
bd4a23b287 | ||
|
|
1b8c4d9f08 | ||
|
|
a1187decb5 | ||
|
|
b9d7aa182d | ||
|
|
b908c1118d | ||
|
|
fab776764f | ||
|
|
f3e17e399d | ||
|
|
3706ca873b | ||
|
|
10c565f32b | ||
|
|
d237e5b9e6 | ||
|
|
3c7e1ce12f | ||
|
|
f422f64325 | ||
|
|
df0656b345 | ||
|
|
1fc9c56c8f | ||
|
|
893a013ae9 | ||
|
|
6d3812d1d0 | ||
|
|
6422aec780 | ||
|
|
fcd7b8a825 | ||
|
|
575da1f574 | ||
|
|
3a507f5bf6 | ||
|
|
a3d6e3740c | ||
|
|
53e0330e21 | ||
|
|
f935c1e28a | ||
|
|
6a0c708224 | ||
|
|
a407d2d94d | ||
|
|
53605bd6e8 | ||
|
|
944faaa927 | ||
|
|
fb7cfc09de | ||
|
|
b9ae73e322 | ||
|
|
c28dbb6b9b | ||
|
|
dcc26b67a6 | ||
|
|
2627d320f3 | ||
|
|
fd4bc28835 | ||
|
|
63e4d588a2 | ||
|
|
feb1680909 | ||
|
|
9d21489b8e | ||
|
|
e70ed1900f | ||
|
|
d65b5a089a | ||
|
|
84643647cc | ||
|
|
57f487db6d | ||
|
|
0862cad2ce | ||
|
|
5ae4f59315 | ||
|
|
3fc3005ba5 | ||
|
|
20f48edd00 | ||
|
|
b854aad830 | ||
|
|
6cbe03f656 | ||
|
|
63cac9a75e | ||
|
|
08616f1057 | ||
|
|
e6193b1020 | ||
|
|
f28b9903f3 | ||
|
|
7bf2d119ea | ||
|
|
527bded1b2 | ||
|
|
1208c53ebb | ||
|
|
973efa2d27 | ||
|
|
d09588b915 | ||
|
|
19aa313753 | ||
|
|
9db12cd25f | ||
|
|
69e785e6ee | ||
|
|
159fce6839 |
2
.github/workflows/check.yml
vendored
2
.github/workflows/check.yml
vendored
@@ -11,4 +11,4 @@ jobs:
|
|||||||
- name: Run ShellCheck
|
- name: Run ShellCheck
|
||||||
uses: ludeeus/action-shellcheck@master
|
uses: ludeeus/action-shellcheck@master
|
||||||
env:
|
env:
|
||||||
SHELLCHECK_OPTS: -x --source-path=src -e SC2001 -e SC2002 -e SC2223 -e SC2034 -e SC2064 -e SC2317 -e SC2028 -e SC2153 -e SC2004
|
SHELLCHECK_OPTS: -x --source-path=src -e SC2001 -e SC2034 -e SC2064 -e SC2317 -e SC2153 -e SC2028
|
||||||
|
|||||||
28
Dockerfile
28
Dockerfile
@@ -2,7 +2,7 @@ FROM qemux/qemu-host as builder
|
|||||||
|
|
||||||
# FROM golang as builder
|
# FROM golang as builder
|
||||||
# WORKDIR /
|
# WORKDIR /
|
||||||
# RUN git clone https://github.com/qemu-tools/qemu-host.git
|
# RUN git clone https://github.com/qemus/qemu-host.git
|
||||||
# WORKDIR /qemu-host/src
|
# WORKDIR /qemu-host/src
|
||||||
# RUN go mod download
|
# RUN go mod download
|
||||||
# RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o /qemu-host.bin .
|
# RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o /qemu-host.bin .
|
||||||
@@ -10,11 +10,12 @@ FROM qemux/qemu-host as builder
|
|||||||
FROM debian:trixie-slim
|
FROM debian:trixie-slim
|
||||||
|
|
||||||
ARG TARGETPLATFORM
|
ARG TARGETPLATFORM
|
||||||
ARG DEBCONF_NOWARNINGS="yes"
|
ARG DEBCONF_NOWARNINGS "yes"
|
||||||
ARG DEBIAN_FRONTEND noninteractive
|
ARG DEBIAN_FRONTEND "noninteractive"
|
||||||
|
ARG DEBCONF_NONINTERACTIVE_SEEN "true"
|
||||||
|
|
||||||
RUN apt-get update && apt-get -y upgrade \
|
RUN if [ "$TARGETPLATFORM" != "linux/amd64" ]; then extra="qemu-user"; fi \
|
||||||
&& if [ "$TARGETPLATFORM" != "linux/amd64" ]; then extra="qemu-user"; fi \
|
&& apt-get update \
|
||||||
&& apt-get --no-install-recommends -y install \
|
&& apt-get --no-install-recommends -y install \
|
||||||
jq \
|
jq \
|
||||||
tini \
|
tini \
|
||||||
@@ -23,11 +24,12 @@ RUN apt-get update && apt-get -y upgrade \
|
|||||||
wget \
|
wget \
|
||||||
fdisk \
|
fdisk \
|
||||||
unzip \
|
unzip \
|
||||||
socat \
|
nginx \
|
||||||
procps \
|
procps \
|
||||||
xz-utils \
|
xz-utils \
|
||||||
iptables \
|
iptables \
|
||||||
iproute2 \
|
iproute2 \
|
||||||
|
apt-utils \
|
||||||
dnsmasq \
|
dnsmasq \
|
||||||
fakeroot \
|
fakeroot \
|
||||||
net-tools \
|
net-tools \
|
||||||
@@ -37,25 +39,25 @@ RUN apt-get update && apt-get -y upgrade \
|
|||||||
qemu-system-x86 \
|
qemu-system-x86 \
|
||||||
"$extra" \
|
"$extra" \
|
||||||
&& apt-get clean \
|
&& apt-get clean \
|
||||||
|
&& unlink /etc/nginx/sites-enabled/default \
|
||||||
|
&& sed -i 's/^worker_processes.*/worker_processes 1;/' /etc/nginx/nginx.conf \
|
||||||
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
|
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
|
||||||
|
|
||||||
COPY ./src /run/
|
COPY ./src /run/
|
||||||
|
COPY ./web /var/www/
|
||||||
COPY --from=builder /qemu-host.bin /run/host.bin
|
COPY --from=builder /qemu-host.bin /run/host.bin
|
||||||
|
|
||||||
RUN chmod +x /run/*.sh && chmod +x /run/*.bin
|
RUN chmod +x /run/*.sh && chmod +x /run/*.bin
|
||||||
|
RUN mv /var/www/nginx.conf /etc/nginx/sites-enabled/web.conf
|
||||||
|
|
||||||
VOLUME /storage
|
VOLUME /storage
|
||||||
|
EXPOSE 22 139 445 5000
|
||||||
EXPOSE 22
|
|
||||||
EXPOSE 80
|
|
||||||
EXPOSE 139
|
|
||||||
EXPOSE 445
|
|
||||||
EXPOSE 5000
|
|
||||||
|
|
||||||
ENV RAM_SIZE "1G"
|
ENV RAM_SIZE "1G"
|
||||||
ENV DISK_SIZE "16G"
|
ENV DISK_SIZE "16G"
|
||||||
ENV CPU_CORES "1"
|
ENV CPU_CORES "1"
|
||||||
|
|
||||||
ARG VERSION_ARG="0.0"
|
ARG VERSION_ARG "0.0"
|
||||||
RUN echo "$VERSION_ARG" > /run/version
|
RUN echo "$VERSION_ARG" > /run/version
|
||||||
|
|
||||||
HEALTHCHECK --interval=60s --start-period=45s --retries=2 CMD /run/check.sh
|
HEALTHCHECK --interval=60s --start-period=45s --retries=2 CMD /run/check.sh
|
||||||
|
|||||||
140
agent/agent.sh
140
agent/agent.sh
@@ -1,140 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
set -u
|
|
||||||
|
|
||||||
VERSION="9"
|
|
||||||
HEADER="VirtualDSM Agent"
|
|
||||||
|
|
||||||
# Functions
|
|
||||||
|
|
||||||
error () { echo -e "\E[1;31m❯ ERROR: $1\E[0m" ; }
|
|
||||||
info () { echo -e "\E[1;34m❯\E[1;36m $1\E[0m" ; }
|
|
||||||
|
|
||||||
finish() {
|
|
||||||
|
|
||||||
echo "❯ $HEADER: Shutting down.."
|
|
||||||
exit
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
function checkNMI {
|
|
||||||
|
|
||||||
local nmi
|
|
||||||
nmi=$(cat /proc/interrupts | grep NMI | sed 's/[^1-9]*//g')
|
|
||||||
|
|
||||||
if [ "$nmi" != "" ]; then
|
|
||||||
|
|
||||||
info "Received shutdown request through NMI.."
|
|
||||||
|
|
||||||
/usr/syno/sbin/synoshutdown -s > /dev/null
|
|
||||||
finish
|
|
||||||
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
function downloadUpdate {
|
|
||||||
|
|
||||||
TMP="/tmp/agent.sh"
|
|
||||||
rm -f "${TMP}"
|
|
||||||
|
|
||||||
# Auto update the agent
|
|
||||||
|
|
||||||
URL="https://raw.githubusercontent.com/vdsm/virtual-dsm/master/agent/agent.sh"
|
|
||||||
|
|
||||||
remote_size=$(curl -sIk -m 4 "${URL}" | grep -i "content-length:" | tr -d " \t" | cut -d ':' -f 2)
|
|
||||||
remote_size=${remote_size//$'\r'}
|
|
||||||
|
|
||||||
[[ "$remote_size" == "" || "$remote_size" == "0" ]] && return
|
|
||||||
|
|
||||||
remote_size=$(($remote_size+0))
|
|
||||||
((remote_size<100)) && return
|
|
||||||
|
|
||||||
SCRIPT=$(readlink -f "${BASH_SOURCE[0]}")
|
|
||||||
local_size=$(stat -c%s "$SCRIPT")
|
|
||||||
local_size=$(($local_size+0))
|
|
||||||
|
|
||||||
[[ remote_size -eq local_size ]] && return
|
|
||||||
|
|
||||||
if ! curl -sfk -m 10 -o "${TMP}" "${URL}"; then
|
|
||||||
error "$HEADER: curl error ($?)" && return
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ ! -f "${TMP}" ]; then
|
|
||||||
error "$HEADER: update error, file not found.." && return
|
|
||||||
fi
|
|
||||||
|
|
||||||
line=$(head -1 "${TMP}")
|
|
||||||
|
|
||||||
if [[ "$line" != "#!/usr/bin/env bash" ]]; then
|
|
||||||
error "$HEADER: update error, invalid header: $line" && return
|
|
||||||
fi
|
|
||||||
|
|
||||||
if cmp --silent -- "${TMP}" "${SCRIPT}"; then
|
|
||||||
error "$HEADER: update file is already equal? (${local_size} / ${remote_size})" && return
|
|
||||||
fi
|
|
||||||
|
|
||||||
mv -f "${TMP}" "${SCRIPT}"
|
|
||||||
chmod 755 "${SCRIPT}"
|
|
||||||
|
|
||||||
info "$HEADER: succesfully installed update..."
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
function installPackages {
|
|
||||||
|
|
||||||
for filename in /usr/local/packages/*.spk; do
|
|
||||||
if [ -f "$filename" ]; then
|
|
||||||
|
|
||||||
BASE=$(basename "$filename" .spk)
|
|
||||||
BASE="${BASE%%-*}"
|
|
||||||
|
|
||||||
[[ $BASE == "ActiveInsight" ]] && continue
|
|
||||||
|
|
||||||
info "Installing package ${BASE}.."
|
|
||||||
|
|
||||||
/usr/syno/bin/synopkg install "$filename" > /dev/null
|
|
||||||
/usr/syno/bin/synopkg start "$BASE" > /dev/null &
|
|
||||||
|
|
||||||
rm "$filename"
|
|
||||||
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
trap finish SIGINT SIGTERM
|
|
||||||
|
|
||||||
ts=$(date +%s%N)
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
echo "❯ Started $HEADER v$VERSION..."
|
|
||||||
|
|
||||||
checkNMI
|
|
||||||
|
|
||||||
# Install packages
|
|
||||||
|
|
||||||
first_run=false
|
|
||||||
|
|
||||||
for filename in /usr/local/packages/*.spk; do
|
|
||||||
if [ -f "$filename" ]; then
|
|
||||||
first_run=true
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
if [ "$first_run" = true ]; then
|
|
||||||
|
|
||||||
installPackages
|
|
||||||
|
|
||||||
else
|
|
||||||
|
|
||||||
downloadUpdate
|
|
||||||
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Wait for NMI interrupt as a shutdown signal
|
|
||||||
|
|
||||||
while true; do
|
|
||||||
|
|
||||||
checkNMI
|
|
||||||
sleep 2 & wait $!
|
|
||||||
|
|
||||||
done
|
|
||||||
@@ -1,87 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
PIDFILE="/var/run/agent.pid"
|
|
||||||
SCRIPT="/usr/local/bin/agent.sh"
|
|
||||||
|
|
||||||
error () { echo -e "\E[1;31m❯ ERROR: $1\E[0m" ; }
|
|
||||||
info () { echo -e "\E[1;34m❯\E[1;36m $1\E[0m" ; }
|
|
||||||
|
|
||||||
status() {
|
|
||||||
|
|
||||||
if [ -f "$PIDFILE" ] && kill -0 "$(cat "$PIDFILE")"; then
|
|
||||||
echo 'Service running'
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
start() {
|
|
||||||
|
|
||||||
if [ -f "$PIDFILE" ] && kill -0 "$(cat "$PIDFILE")"; then
|
|
||||||
echo 'Service already running'
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo 'Starting agent service...'
|
|
||||||
chmod 666 /dev/ttyS0
|
|
||||||
|
|
||||||
if [ ! -f "$SCRIPT" ]; then
|
|
||||||
|
|
||||||
URL="https://raw.githubusercontent.com/vdsm/virtual-dsm/master/agent/agent.sh"
|
|
||||||
|
|
||||||
if ! curl -sfk -m 10 -o "${SCRIPT}" "${URL}"; then
|
|
||||||
error 'Failed to download agent script.' > /dev/ttyS0
|
|
||||||
rm -f "${SCRIPT}"
|
|
||||||
return 1
|
|
||||||
else
|
|
||||||
info 'Agent script was missing?' > /dev/ttyS0
|
|
||||||
fi
|
|
||||||
|
|
||||||
chmod 755 "${SCRIPT}"
|
|
||||||
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "-" > /var/lock/subsys/agent.sh
|
|
||||||
"$SCRIPT" &> /dev/ttyS0 & echo $! > "$PIDFILE"
|
|
||||||
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
stop() {
|
|
||||||
|
|
||||||
if [ ! -f "$PIDFILE" ] || ! kill -0 "$(cat "$PIDFILE")"; then
|
|
||||||
echo 'Service not running'
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo 'Stopping agent service...'
|
|
||||||
|
|
||||||
chmod 666 /dev/ttyS0
|
|
||||||
info 'Stopping agent service...' > /dev/ttyS0
|
|
||||||
|
|
||||||
kill -15 "$(cat "$PIDFILE")" && rm -f "$PIDFILE"
|
|
||||||
rm -f /var/lock/subsys/agent.sh
|
|
||||||
|
|
||||||
echo 'Service stopped'
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
case "$1" in
|
|
||||||
start)
|
|
||||||
start
|
|
||||||
;;
|
|
||||||
stop)
|
|
||||||
stop
|
|
||||||
;;
|
|
||||||
status)
|
|
||||||
status
|
|
||||||
;;
|
|
||||||
restart)
|
|
||||||
stop
|
|
||||||
start
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
echo "Usage: $0 {start|stop|restart}"
|
|
||||||
exit 1
|
|
||||||
esac
|
|
||||||
@@ -9,8 +9,6 @@ services:
|
|||||||
CPU_CORES: "1"
|
CPU_CORES: "1"
|
||||||
devices:
|
devices:
|
||||||
- /dev/kvm
|
- /dev/kvm
|
||||||
- /dev/net/tun
|
|
||||||
- /dev/vhost-net
|
|
||||||
device_cgroup_rules:
|
device_cgroup_rules:
|
||||||
- 'c *:* rwm'
|
- 'c *:* rwm'
|
||||||
cap_add:
|
cap_add:
|
||||||
|
|||||||
74
readme.md
74
readme.md
@@ -1,4 +1,4 @@
|
|||||||
<h1 align="center">Virtual DSM for Docker<br />
|
<h1 align="center">Virtual DSM<br />
|
||||||
<div align="center">
|
<div align="center">
|
||||||
<img src="https://github.com/vdsm/virtual-dsm/raw/master/.github/screen.jpg" title="Screenshot" style="max-width:100%;" width="432" />
|
<img src="https://github.com/vdsm/virtual-dsm/raw/master/.github/screen.jpg" title="Screenshot" style="max-width:100%;" width="432" />
|
||||||
</div>
|
</div>
|
||||||
@@ -17,7 +17,7 @@ Virtual DSM in a docker container.
|
|||||||
|
|
||||||
- Multiple disks
|
- Multiple disks
|
||||||
- KVM acceleration
|
- KVM acceleration
|
||||||
- GPU passthrough
|
- GPU pass-through
|
||||||
- Upgrades supported
|
- Upgrades supported
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
@@ -29,7 +29,7 @@ version: "3"
|
|||||||
services:
|
services:
|
||||||
dsm:
|
dsm:
|
||||||
container_name: dsm
|
container_name: dsm
|
||||||
image: vdsm/virtual-dsm:latest
|
image: vdsm/virtual-dsm
|
||||||
environment:
|
environment:
|
||||||
DISK_SIZE: "16G"
|
DISK_SIZE: "16G"
|
||||||
devices:
|
devices:
|
||||||
@@ -47,12 +47,24 @@ services:
|
|||||||
Via `docker run`
|
Via `docker run`
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker run -it --rm -p 5000:5000 --device=/dev/kvm --cap-add NET_ADMIN --stop-timeout 60 vdsm/virtual-dsm:latest
|
docker run -it --rm -p 5000:5000 --device=/dev/kvm --cap-add NET_ADMIN --stop-timeout 60 vdsm/virtual-dsm
|
||||||
```
|
```
|
||||||
|
|
||||||
## FAQ
|
## FAQ
|
||||||
|
|
||||||
* ### How do I change the size of the virtual disk?
|
* ### How do I use it?
|
||||||
|
|
||||||
|
Very simple! These are the steps:
|
||||||
|
|
||||||
|
- Start the container and get some coffee.
|
||||||
|
|
||||||
|
- Connect to port 5000 of the container in your web browser.
|
||||||
|
|
||||||
|
- Wait until DSM is ready, choose an username and password, and you will be taken to the desktop.
|
||||||
|
|
||||||
|
- Enjoy your brand new machine, and don't forget to star this repo!
|
||||||
|
|
||||||
|
* ### 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 16 GB, locate the `DISK_SIZE` setting in your compose file and modify it to your preferred capacity:
|
||||||
|
|
||||||
@@ -63,9 +75,9 @@ docker run -it --rm -p 5000:5000 --device=/dev/kvm --cap-add NET_ADMIN --stop-ti
|
|||||||
|
|
||||||
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 change the location of the virtual disk?
|
* ### How do I change the storage location?
|
||||||
|
|
||||||
To change the location of the virtual disk, include the following bind mount in your compose file:
|
To change the storage location, include the following bind mount in your compose file:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
volumes:
|
volumes:
|
||||||
@@ -74,7 +86,20 @@ docker run -it --rm -p 5000:5000 --device=/dev/kvm --cap-add NET_ADMIN --stop-ti
|
|||||||
|
|
||||||
Replace the example path `/var/dsm` with the desired storage folder.
|
Replace the example path `/var/dsm` with the desired storage folder.
|
||||||
|
|
||||||
* ### How do I add multiple disks?
|
* ### How do I create a growable disk?
|
||||||
|
|
||||||
|
By default, the entire capacity of the disk is 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"
|
||||||
|
```
|
||||||
|
|
||||||
|
Please note that this may reduce the write performance of the disk.
|
||||||
|
|
||||||
|
* ### 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:
|
||||||
|
|
||||||
@@ -87,23 +112,26 @@ docker run -it --rm -p 5000:5000 --device=/dev/kvm --cap-add NET_ADMIN --stop-ti
|
|||||||
- /mnt/data/example:/storage3
|
- /mnt/data/example:/storage3
|
||||||
```
|
```
|
||||||
|
|
||||||
* ### How do I create a growable disk?
|
* ### How do I pass-through a disk?
|
||||||
|
|
||||||
By default, the entire capacity of the disk is reserved in advance.
|
It is possible to pass-through disk devices directly by adding them to your compose file in this way:
|
||||||
|
|
||||||
To create a growable disk that only allocates space that is actually used, add the following environment variables:
|
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
environment:
|
environment:
|
||||||
ALLOCATE: "N"
|
DEVICE2: "/dev/sda"
|
||||||
DISK_FMT: "qcow2"
|
DEVICE3: "/dev/sdb"
|
||||||
|
devices:
|
||||||
|
- /dev/sda
|
||||||
|
- /dev/sdb
|
||||||
```
|
```
|
||||||
|
|
||||||
Please note that this may reduce the write performance of the disk.
|
Please note that the device needs to be totally empty (without any partition table) otherwise DSM does not always format it into a volume.
|
||||||
|
|
||||||
|
Do NOT use this feature with the goal of sharing files from the host, they will all be lost without warning when DSM creates the volume.
|
||||||
|
|
||||||
* ### How do I increase the amount of CPU or RAM?
|
* ### How do I increase the amount of CPU or RAM?
|
||||||
|
|
||||||
By default, a single core and 1 GB of RAM are allocated to the container.
|
By default, a single CPU core and 1 GB of RAM are allocated to the container.
|
||||||
|
|
||||||
To increase this, add the following environment variables:
|
To increase this, add the following environment variables:
|
||||||
|
|
||||||
@@ -122,7 +150,7 @@ docker run -it --rm -p 5000:5000 --device=/dev/kvm --cap-add NET_ADMIN --stop-ti
|
|||||||
sudo kvm-ok
|
sudo kvm-ok
|
||||||
```
|
```
|
||||||
|
|
||||||
If you receive an error from `kvm-ok` indicating that KVM acceleration can't be used, check your BIOS settings.
|
If you receive an error from `kvm-ok` indicating that KVM acceleration can't be used, check the virtualization settings in the BIOS.
|
||||||
|
|
||||||
* ### How do I assign an individual IP address to the container?
|
* ### How do I assign an individual IP address to the container?
|
||||||
|
|
||||||
@@ -156,11 +184,11 @@ docker run -it --rm -p 5000:5000 --device=/dev/kvm --cap-add NET_ADMIN --stop-ti
|
|||||||
external: true
|
external: true
|
||||||
```
|
```
|
||||||
|
|
||||||
An added benefit of this approach is that you won't have to perform any port mapping anymore since all ports will be exposed by default.
|
An added benefit of this approach is that you won't have to perform any port mapping anymore, since all ports will be exposed by default.
|
||||||
|
|
||||||
Please note that this IP address won't be accessible from the Docker host due to the design of macvlan, which doesn't permit communication between the two. If this is a concern, you need to create a [second macvlan](https://blog.oddbit.com/post/2018-03-12-using-docker-macvlan-networks/#host-access) as a workaround.
|
Please note that this IP address won't be accessible from the Docker host due to the design of macvlan, which doesn't permit communication between the two. If this is a concern, you need to create a [second macvlan](https://blog.oddbit.com/post/2018-03-12-using-docker-macvlan-networks/#host-access) as a workaround.
|
||||||
|
|
||||||
* ### How can the container acquire an IP address from my router?
|
* ### How can DSM acquire an IP address from my router?
|
||||||
|
|
||||||
After configuring the container for macvlan (see above), it is possible for DSM to become part of your home network by requesting an IP from your router, just like your other devices.
|
After configuring the container for macvlan (see above), it is possible for DSM to become part of your home network by requesting an IP from your router, just like your other devices.
|
||||||
|
|
||||||
@@ -173,11 +201,11 @@ docker run -it --rm -p 5000:5000 --device=/dev/kvm --cap-add NET_ADMIN --stop-ti
|
|||||||
- 'c *:* rwm'
|
- 'c *:* rwm'
|
||||||
```
|
```
|
||||||
|
|
||||||
Please note that even if you don't want DHCP, it's still recommended to enable this feature as it prevents NAT issues and increases performance by using a `macvtap` interface. In that case just set a static IP from the DSM control panel after you enabled this mode.
|
Please note that even if you don't want DHCP, it's still recommended to enable this feature, as it prevents NAT issues and increases performance by using a `macvtap` interface. In that case, just set a static IP from the DSM control panel after you enabled this mode.
|
||||||
|
|
||||||
* ### How do I passthrough the GPU?
|
* ### How do I pass-through the GPU?
|
||||||
|
|
||||||
To passthrough your Intel GPU, add the following lines to your compose file:
|
To pass-through your Intel GPU, add the following lines to your compose file:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
environment:
|
environment:
|
||||||
@@ -190,7 +218,7 @@ docker run -it --rm -p 5000:5000 --device=/dev/kvm --cap-add NET_ADMIN --stop-ti
|
|||||||
|
|
||||||
* ### How do I install a specific version of vDSM?
|
* ### How do I install a specific version of vDSM?
|
||||||
|
|
||||||
By default, version 7.2.1 will be installed, but if you prefer an older version, you can add its download URL to your compose file as follows:
|
By default, version 7.2 will be installed, but if you prefer an older version, you can add its download URL to your compose file as follows:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
environment:
|
environment:
|
||||||
|
|||||||
12
src/check.sh
12
src/check.sh
@@ -1,15 +1,15 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
set -Eeuo pipefail
|
set -Eeuo pipefail
|
||||||
|
|
||||||
: ${VM_NET_DEV:='eth0'}
|
[ -f "/run/shm/qemu.end" ] && echo "QEMU is shutting down.." && exit 1
|
||||||
|
[ ! -f "/run/shm/qemu.pid" ] && echo "QEMU is not running yet.." && exit 0
|
||||||
|
|
||||||
[ -f "/run/qemu.count" ] && echo "QEMU is shutting down.." && exit 1
|
file="/run/shm/dsm.url"
|
||||||
[ ! -f "/run/qemu.pid" ] && echo "QEMU not running yet.." && exit 0
|
address="/run/shm/qemu.ip"
|
||||||
|
|
||||||
file="/run/dsm.url"
|
|
||||||
[ ! -f "$file" ] && echo "DSM has not enabled networking yet.." && exit 1
|
[ ! -f "$file" ] && echo "DSM has not enabled networking yet.." && exit 1
|
||||||
|
|
||||||
location=$(cat "$file")
|
location=$(<"$file")
|
||||||
|
|
||||||
if ! curl -m 20 -ILfSs "http://$location/" > /dev/null; then
|
if ! curl -m 20 -ILfSs "http://$location/" > /dev/null; then
|
||||||
|
|
||||||
@@ -19,7 +19,7 @@ if ! curl -m 20 -ILfSs "http://$location/" > /dev/null; then
|
|||||||
echo "Failed to reach DSM at port $port"
|
echo "Failed to reach DSM at port $port"
|
||||||
else
|
else
|
||||||
echo "Failed to reach DSM at http://$location"
|
echo "Failed to reach DSM at http://$location"
|
||||||
ip=$(ip address show dev "$VM_NET_DEV" | grep inet | awk '/inet / { print $2 }' | cut -f1 -d/)
|
ip=$(<"$address")
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "You might need to whitelist IP $ip in the DSM firewall." && exit 1
|
echo "You might need to whitelist IP $ip in the DSM firewall." && exit 1
|
||||||
|
|||||||
@@ -1,20 +1,15 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
set -Eeuo pipefail
|
set -Eeuo pipefail
|
||||||
|
|
||||||
DEF_OPTS="-nographic -nodefaults -boot strict=on -display none"
|
DEF_OPTS="-nodefaults -boot strict=on"
|
||||||
RAM_OPTS=$(echo "-m $RAM_SIZE" | sed 's/MB/M/g;s/GB/G/g;s/TB/T/g')
|
RAM_OPTS=$(echo "-m $RAM_SIZE" | sed 's/MB/M/g;s/GB/G/g;s/TB/T/g')
|
||||||
CPU_OPTS="-cpu $CPU_MODEL -smp $CPU_CORES,sockets=1,dies=1,cores=$CPU_CORES,threads=1"
|
CPU_OPTS="-cpu $CPU_MODEL -smp $CPU_CORES,sockets=1,dies=1,cores=$CPU_CORES,threads=1"
|
||||||
MAC_OPTS="-machine type=q35,usb=off,dump-guest-core=off,hpet=off${KVM_OPTS}"
|
MAC_OPTS="-machine type=q35,usb=off,dump-guest-core=off,hpet=off${KVM_OPTS}"
|
||||||
EXTRA_OPTS="-device virtio-balloon-pci,id=balloon0,bus=pcie.0,addr=0x4"
|
DEV_OPTS="-device virtio-balloon-pci,id=balloon0,bus=pcie.0,addr=0x4"
|
||||||
EXTRA_OPTS="$EXTRA_OPTS -object rng-random,id=objrng0,filename=/dev/urandom"
|
DEV_OPTS="$DEV_OPTS -object rng-random,id=objrng0,filename=/dev/urandom"
|
||||||
EXTRA_OPTS="$EXTRA_OPTS -device virtio-rng-pci,rng=objrng0,id=rng0,bus=pcie.0,addr=0x1c"
|
DEV_OPTS="$DEV_OPTS -device virtio-rng-pci,rng=objrng0,id=rng0,bus=pcie.0,addr=0x1c"
|
||||||
|
|
||||||
if [[ "$GPU" == [Yy1]* ]] && [[ "$ARCH" == "amd64" ]]; then
|
ARGS="$DEF_OPTS $CPU_OPTS $RAM_OPTS $MAC_OPTS $DISPLAY_OPTS $MON_OPTS $SERIAL_OPTS $NET_OPTS $DISK_OPTS $DEV_OPTS $ARGUMENTS"
|
||||||
DEF_OPTS="-nodefaults -boot strict=on -display egl-headless,rendernode=/dev/dri/renderD128"
|
|
||||||
DEF_OPTS="$DEF_OPTS -device virtio-vga,id=video0,max_outputs=1,bus=pcie.0,addr=0x1"
|
|
||||||
fi
|
|
||||||
|
|
||||||
ARGS="$DEF_OPTS $CPU_OPTS $RAM_OPTS $MAC_OPTS $MON_OPTS $SERIAL_OPTS $NET_OPTS $DISK_OPTS $EXTRA_OPTS $ARGUMENTS"
|
|
||||||
ARGS=$(echo "$ARGS" | sed 's/\t/ /g' | tr -s ' ')
|
ARGS=$(echo "$ARGS" | sed 's/\t/ /g' | tr -s ' ')
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
|
|||||||
146
src/disk.sh
146
src/disk.sh
@@ -3,12 +3,12 @@ set -Eeuo pipefail
|
|||||||
|
|
||||||
# Docker environment variables
|
# Docker environment variables
|
||||||
|
|
||||||
: ${DISK_IO:='native'} # I/O Mode, can be set to 'native', 'threads' or 'io_turing'
|
: "${DISK_IO:="native"}" # I/O Mode, can be set to 'native', 'threads' or 'io_turing'
|
||||||
: ${DISK_FMT:='raw'} # Disk file format, 'raw' by default for best performance
|
: "${DISK_FMT:="raw"}" # Disk file format, 'raw' by default for best performance
|
||||||
: ${DISK_CACHE:='none'} # Caching mode, can be set to 'writeback' for better performance
|
: "${DISK_FLAGS:=""}" # Specifies the options for use with the qcow2 disk format
|
||||||
: ${DISK_DISCARD:='on'} # Controls whether unmap (TRIM) commands are passed to the host.
|
: "${DISK_CACHE:="none"}" # Caching mode, can be set to 'writeback' for better performance
|
||||||
: ${DISK_ROTATION:='1'} # Rotation rate, set to 1 for SSD storage and increase for HDD
|
: "${DISK_DISCARD:="on"}" # Controls whether unmap (TRIM) commands are passed to the host.
|
||||||
: ${DISK_FLAGS:=''} # Specifies the options for use with the qcow2 disk format
|
: "${DISK_ROTATION:="1"}" # Rotation rate, set to 1 for SSD storage and increase for HDD
|
||||||
|
|
||||||
BOOT="$STORAGE/$BASE.boot.img"
|
BOOT="$STORAGE/$BASE.boot.img"
|
||||||
SYSTEM="$STORAGE/$BASE.system.img"
|
SYSTEM="$STORAGE/$BASE.system.img"
|
||||||
@@ -17,11 +17,11 @@ SYSTEM="$STORAGE/$BASE.system.img"
|
|||||||
[ ! -f "$SYSTEM" ] && error "Virtual DSM system-image does not exist ($SYSTEM)" && exit 82
|
[ ! -f "$SYSTEM" ] && error "Virtual DSM system-image does not exist ($SYSTEM)" && exit 82
|
||||||
|
|
||||||
DISK_OPTS="\
|
DISK_OPTS="\
|
||||||
-object iothread,id=io1 -object iothread,id=io2 \
|
-object iothread,id=io2 \
|
||||||
-device virtio-scsi-pci,id=hw-synoboot,iothread=io1,bus=pcie.0,addr=0xa \
|
-device virtio-scsi-pci,id=hw-synoboot,iothread=io2,bus=pcie.0,addr=0xa \
|
||||||
-drive file=$BOOT,if=none,id=drive-synoboot,format=raw,cache=$DISK_CACHE,aio=$DISK_IO,discard=$DISK_DISCARD,detect-zeroes=on \
|
-drive file=$BOOT,if=none,id=drive-synoboot,format=raw,cache=$DISK_CACHE,aio=$DISK_IO,discard=$DISK_DISCARD,detect-zeroes=on \
|
||||||
-device scsi-hd,bus=hw-synoboot.0,channel=0,scsi-id=0,lun=0,drive=drive-synoboot,id=synoboot0,rotation_rate=$DISK_ROTATION,bootindex=1 \
|
-device scsi-hd,bus=hw-synoboot.0,channel=0,scsi-id=0,lun=0,drive=drive-synoboot,id=synoboot0,rotation_rate=$DISK_ROTATION,bootindex=1 \
|
||||||
-device virtio-scsi-pci,id=hw-synosys,iothread=io1,bus=pcie.0,addr=0xb \
|
-device virtio-scsi-pci,id=hw-synosys,iothread=io2,bus=pcie.0,addr=0xb \
|
||||||
-drive file=$SYSTEM,if=none,id=drive-synosys,format=raw,cache=$DISK_CACHE,aio=$DISK_IO,discard=$DISK_DISCARD,detect-zeroes=on \
|
-drive file=$SYSTEM,if=none,id=drive-synosys,format=raw,cache=$DISK_CACHE,aio=$DISK_IO,discard=$DISK_DISCARD,detect-zeroes=on \
|
||||||
-device scsi-hd,bus=hw-synosys.0,channel=0,scsi-id=0,lun=0,drive=drive-synosys,id=synosys0,rotation_rate=$DISK_ROTATION,bootindex=2"
|
-device scsi-hd,bus=hw-synosys.0,channel=0,scsi-id=0,lun=0,drive=drive-synosys,id=synosys0,rotation_rate=$DISK_ROTATION,bootindex=2"
|
||||||
|
|
||||||
@@ -61,8 +61,8 @@ getSize() {
|
|||||||
local DISK_FILE=$1
|
local DISK_FILE=$1
|
||||||
local DISK_EXT DISK_FMT
|
local DISK_EXT DISK_FMT
|
||||||
|
|
||||||
DISK_EXT="$(echo "${DISK_FILE//*./}" | sed 's/^.*\.//')"
|
DISK_EXT=$(echo "${DISK_FILE//*./}" | sed 's/^.*\.//')
|
||||||
DISK_FMT="$(ext2fmt "$DISK_EXT")"
|
DISK_FMT=$(ext2fmt "$DISK_EXT")
|
||||||
|
|
||||||
case "${DISK_FMT,,}" in
|
case "${DISK_FMT,,}" in
|
||||||
raw)
|
raw)
|
||||||
@@ -83,7 +83,7 @@ isCow() {
|
|||||||
if [[ "${FS,,}" == "xfs" || "${FS,,}" == "zfs" || "${FS,,}" == "btrfs" || "${FS,,}" == "bcachefs" ]]; then
|
if [[ "${FS,,}" == "xfs" || "${FS,,}" == "zfs" || "${FS,,}" == "btrfs" || "${FS,,}" == "bcachefs" ]]; then
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,7 +112,9 @@ createDisk() {
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
info "Creating a $DISK_TYPE $DISK_DESC image in $DISK_FMT format with a size of $DISK_SPACE..."
|
MSG="Creating a $DISK_TYPE $DISK_DESC image in $DISK_FMT format with a size of $DISK_SPACE..."
|
||||||
|
info "$MSG" && html "$MSG"
|
||||||
|
|
||||||
local FAIL="Could not create a $DISK_TYPE $DISK_FMT $DISK_DESC image of $DISK_SPACE ($DISK_FILE)"
|
local FAIL="Could not create a $DISK_TYPE $DISK_FMT $DISK_DESC image of $DISK_SPACE ($DISK_FILE)"
|
||||||
|
|
||||||
case "${DISK_FMT,,}" in
|
case "${DISK_FMT,,}" in
|
||||||
@@ -126,7 +128,7 @@ createDisk() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "$ALLOCATE" == [Nn]* ]]; then
|
if [[ "$ALLOCATE" == [Nn]* ]]; then
|
||||||
|
|
||||||
# Create an empty file
|
# Create an empty file
|
||||||
if ! truncate -s "$DATA_SIZE" "$DISK_FILE"; then
|
if ! truncate -s "$DATA_SIZE" "$DISK_FILE"; then
|
||||||
rm -f "$DISK_FILE"
|
rm -f "$DISK_FILE"
|
||||||
@@ -195,7 +197,9 @@ resizeDisk() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
local GB=$(( (CUR_SIZE + 1073741823)/1073741824 ))
|
local GB=$(( (CUR_SIZE + 1073741823)/1073741824 ))
|
||||||
info "Resizing $DISK_DESC from ${GB}G to $DISK_SPACE..."
|
MSG="Resizing $DISK_DESC from ${GB}G to $DISK_SPACE..."
|
||||||
|
info "$MSG" && html "$MSG"
|
||||||
|
|
||||||
local FAIL="Could not resize the $DISK_TYPE $DISK_FMT $DISK_DESC image from ${GB}G to $DISK_SPACE ($DISK_FILE)"
|
local FAIL="Could not resize the $DISK_TYPE $DISK_FMT $DISK_DESC image from ${GB}G to $DISK_SPACE ($DISK_FILE)"
|
||||||
|
|
||||||
case "${DISK_FMT,,}" in
|
case "${DISK_FMT,,}" in
|
||||||
@@ -262,7 +266,8 @@ convertDisk() {
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
info "Converting $DISK_DESC to $DST_FMT, please wait until completed..."
|
MSG="Converting $DISK_DESC to $DST_FMT, please wait until completed..."
|
||||||
|
info "$MSG" && html "$MSG"
|
||||||
|
|
||||||
local CONV_FLAGS="-p"
|
local CONV_FLAGS="-p"
|
||||||
local DISK_PARAM="$DISK_ALLOC"
|
local DISK_PARAM="$DISK_ALLOC"
|
||||||
@@ -301,7 +306,8 @@ convertDisk() {
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
info "Conversion of $DISK_DESC to $DST_FMT completed succesfully!"
|
MSG="Conversion of $DISK_DESC to $DST_FMT completed succesfully!"
|
||||||
|
info "$MSG" && html "$MSG"
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
@@ -319,6 +325,10 @@ checkFS () {
|
|||||||
info "Warning: the filesystem of $DIR is OverlayFS, this usually means it was binded to an invalid path!"
|
info "Warning: the filesystem of $DIR is OverlayFS, this usually means it was binded to an invalid path!"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [[ "${FS,,}" == "fuse"* ]]; then
|
||||||
|
info "Warning: the filesystem of $DIR is FUSE, this extra layer will negatively affect performance!"
|
||||||
|
fi
|
||||||
|
|
||||||
if isCow "$FS"; then
|
if isCow "$FS"; then
|
||||||
if [ -f "$DISK_FILE" ]; then
|
if [ -f "$DISK_FILE" ]; then
|
||||||
FA=$(lsattr "$DISK_FILE")
|
FA=$(lsattr "$DISK_FILE")
|
||||||
@@ -368,7 +378,7 @@ addDisk () {
|
|||||||
else
|
else
|
||||||
PREV_FMT="qcow2"
|
PREV_FMT="qcow2"
|
||||||
fi
|
fi
|
||||||
PREV_EXT="$(fmt2ext "$PREV_FMT")"
|
PREV_EXT=$(fmt2ext "$PREV_FMT")
|
||||||
|
|
||||||
if [ -f "$DISK_BASE.$PREV_EXT" ] ; then
|
if [ -f "$DISK_BASE.$PREV_EXT" ] ; then
|
||||||
convertDisk "$DISK_BASE.$PREV_EXT" "$PREV_FMT" "$DISK_FILE" "$DISK_FMT" "$DISK_BASE" "$DISK_DESC" "$FS" || exit $?
|
convertDisk "$DISK_BASE.$PREV_EXT" "$PREV_FMT" "$DISK_FILE" "$DISK_FMT" "$DISK_BASE" "$DISK_DESC" "$FS" || exit $?
|
||||||
@@ -397,7 +407,36 @@ addDisk () {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
DISK_EXT="$(fmt2ext "$DISK_FMT")" || exit $?
|
addDevice () {
|
||||||
|
|
||||||
|
local DISK_ID=$1
|
||||||
|
local DISK_DEV=$2
|
||||||
|
local DISK_DESC=$3
|
||||||
|
local DISK_INDEX=$4
|
||||||
|
local DISK_ADDRESS=$5
|
||||||
|
|
||||||
|
[ -z "$DISK_DEV" ] && return 0
|
||||||
|
[ ! -b "$DISK_DEV" ] && error "Device $DISK_DEV cannot be found! Please add it to the 'devices' section of your compose file." && exit 55
|
||||||
|
|
||||||
|
DISK_OPTS="$DISK_OPTS \
|
||||||
|
-device virtio-scsi-pci,id=hw-$DISK_ID,iothread=io2,bus=pcie.0,addr=$DISK_ADDRESS \
|
||||||
|
-drive file=$DISK_DEV,if=none,id=drive-$DISK_ID,format=raw,cache=$DISK_CACHE,aio=$DISK_IO,discard=$DISK_DISCARD,detect-zeroes=on \
|
||||||
|
-device scsi-hd,bus=hw-$DISK_ID.0,channel=0,scsi-id=0,lun=0,drive=drive-$DISK_ID,id=$DISK_ID,rotation_rate=$DISK_ROTATION,bootindex=$DISK_INDEX"
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
html "Initializing disks..."
|
||||||
|
|
||||||
|
DISK_EXT=$(fmt2ext "$DISK_FMT")
|
||||||
|
|
||||||
|
if [ -z "$ALLOCATE" ]; then
|
||||||
|
if [[ "${DISK_FMT,,}" == "raw" ]]; then
|
||||||
|
ALLOCATE="Y"
|
||||||
|
else
|
||||||
|
ALLOCATE="N"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
if [[ "$ALLOCATE" == [Nn]* ]]; then
|
if [[ "$ALLOCATE" == [Nn]* ]]; then
|
||||||
DISK_TYPE="growable"
|
DISK_TYPE="growable"
|
||||||
@@ -440,52 +479,39 @@ if [ ! -f "$DISK3_FILE.img" ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
DISK4_FILE="/storage4/data4"
|
DISK4_FILE="/storage4/data4"
|
||||||
DISK5_FILE="/storage5/data5"
|
|
||||||
DISK6_FILE="/storage6/data6"
|
|
||||||
|
|
||||||
: ${DISK2_SIZE:=''}
|
: "${DISK2_SIZE:=""}"
|
||||||
: ${DISK3_SIZE:=''}
|
: "${DISK3_SIZE:=""}"
|
||||||
: ${DISK4_SIZE:=''}
|
: "${DISK4_SIZE:=""}"
|
||||||
: ${DISK5_SIZE:=''}
|
|
||||||
: ${DISK6_SIZE:=''}
|
|
||||||
|
|
||||||
addDisk "userdata" "$DISK1_FILE" "$DISK_EXT" "disk" "$DISK_SIZE" "3" "0xc" "$DISK_FMT" || exit $?
|
: "${DEVICE:=""}" # Docker variables to passthrough a block device, like /dev/vdc1.
|
||||||
addDisk "userdata2" "$DISK2_FILE" "$DISK_EXT" "disk2" "$DISK2_SIZE" "4" "0xd" "$DISK_FMT" || exit $?
|
: "${DEVICE2:=""}"
|
||||||
addDisk "userdata3" "$DISK3_FILE" "$DISK_EXT" "disk3" "$DISK3_SIZE" "5" "0xe" "$DISK_FMT" || exit $?
|
: "${DEVICE3:=""}"
|
||||||
addDisk "userdata4" "$DISK4_FILE" "$DISK_EXT" "disk4" "$DISK4_SIZE" "9" "0x7" "$DISK_FMT" || exit $?
|
: "${DEVICE4:=""}"
|
||||||
addDisk "userdata5" "$DISK5_FILE" "$DISK_EXT" "disk5" "$DISK5_SIZE" "10" "0x8" "$DISK_FMT" || exit $?
|
|
||||||
addDisk "userdata6" "$DISK6_FILE" "$DISK_EXT" "disk6" "$DISK6_SIZE" "11" "0x9" "$DISK_FMT" || exit $?
|
|
||||||
|
|
||||||
addDevice () {
|
if [ -n "$DEVICE" ]; then
|
||||||
|
addDevice "userdata" "$DEVICE" "device" "3" "0xc" || exit $?
|
||||||
|
else
|
||||||
|
addDisk "userdata" "$DISK1_FILE" "$DISK_EXT" "disk" "$DISK_SIZE" "3" "0xc" "$DISK_FMT" || exit $?
|
||||||
|
fi
|
||||||
|
|
||||||
local DISK_ID=$1
|
if [ -n "$DEVICE2" ]; then
|
||||||
local DISK_DEV=$2
|
addDevice "userdata2" "$DEVICE2" "device2" "4" "0xd" || exit $?
|
||||||
local DISK_INDEX=$3
|
else
|
||||||
local DISK_ADDRESS=$4
|
addDisk "userdata2" "$DISK2_FILE" "$DISK_EXT" "disk2" "$DISK2_SIZE" "4" "0xd" "$DISK_FMT" || exit $?
|
||||||
|
fi
|
||||||
|
|
||||||
[ -z "$DISK_DEV" ] && return 0
|
if [ -n "$DEVICE3" ]; then
|
||||||
[ ! -b "$DISK_DEV" ] && error "Device $DISK_DEV cannot be found! Please add it to the 'devices' section of your compose file." && exit 55
|
addDevice "userdata3" "$DEVICE3" "device3" "5" "0xe" || exit $?
|
||||||
|
else
|
||||||
|
addDisk "userdata3" "$DISK3_FILE" "$DISK_EXT" "disk3" "$DISK3_SIZE" "5" "0xe" "$DISK_FMT" || exit $?
|
||||||
|
fi
|
||||||
|
|
||||||
DISK_OPTS="$DISK_OPTS \
|
if [ -n "$DEVICE4" ]; then
|
||||||
-device virtio-scsi-pci,id=hw-$DISK_ID,iothread=io2,bus=pcie.0,addr=$DISK_ADDRESS \
|
addDevice "userdata4" "$DEVICE4" "device4" "6" "0xf" || exit $?
|
||||||
-drive file=$DISK_DEV,if=none,id=drive-$DISK_ID,format=raw,cache=$DISK_CACHE,aio=$DISK_IO,discard=$DISK_DISCARD,detect-zeroes=on \
|
else
|
||||||
-device scsi-hd,bus=hw-$DISK_ID.0,channel=0,scsi-id=0,lun=0,drive=drive-$DISK_ID,id=$DISK_ID,rotation_rate=$DISK_ROTATION,bootindex=$DISK_INDEX"
|
addDisk "userdata4" "$DISK4_FILE" "$DISK_EXT" "disk4" "$DISK4_SIZE" "6" "0xf" "$DISK_FMT" || exit $?
|
||||||
|
fi
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
: ${DEVICE:=''} # Docker variable to passthrough a block device, like /dev/vdc1.
|
|
||||||
: ${DEVICE2:=''}
|
|
||||||
: ${DEVICE3:=''}
|
|
||||||
: ${DEVICE4:=''}
|
|
||||||
: ${DEVICE5:=''}
|
|
||||||
: ${DEVICE6:=''}
|
|
||||||
|
|
||||||
addDevice "userdata7" "$DEVICE" "6" "0xf" || exit $?
|
|
||||||
addDevice "userdata8" "$DEVICE2" "7" "0x5" || exit $?
|
|
||||||
addDevice "userdata9" "$DEVICE3" "8" "0x6" || exit $?
|
|
||||||
addDevice "userdata4" "$DEVICE4" "9" "0x7" || exit $?
|
|
||||||
addDevice "userdata5" "$DEVICE5" "10" "0x8" || exit $?
|
|
||||||
addDevice "userdata6" "$DEVICE6" "11" "0x9" || exit $?
|
|
||||||
|
|
||||||
|
html "Initialized disks successfully..."
|
||||||
return 0
|
return 0
|
||||||
|
|||||||
@@ -1,10 +1,22 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
set -Eeuo pipefail
|
set -Eeuo pipefail
|
||||||
|
|
||||||
|
# Docker environment variables
|
||||||
|
|
||||||
|
: "${GPU:="N"}" # GPU passthrough
|
||||||
|
: "${VGA:="virtio"}" # VGA adaptor
|
||||||
|
: "${DISPLAY:="none"}" # Display type
|
||||||
|
|
||||||
if [[ "$GPU" != [Yy1]* ]] || [[ "$ARCH" != "amd64" ]]; then
|
if [[ "$GPU" != [Yy1]* ]] || [[ "$ARCH" != "amd64" ]]; then
|
||||||
|
|
||||||
|
[[ "${DISPLAY,,}" == "none" ]] && VGA="none"
|
||||||
|
DISPLAY_OPTS="-display $DISPLAY -vga $VGA"
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
DISPLAY_OPTS="-display egl-headless,rendernode=/dev/dri/renderD128 -vga $VGA"
|
||||||
|
|
||||||
[ ! -d /dev/dri ] && mkdir -m 755 /dev/dri
|
[ ! -d /dev/dri ] && mkdir -m 755 /dev/dri
|
||||||
|
|
||||||
if [ ! -c /dev/dri/card0 ]; then
|
if [ ! -c /dev/dri/card0 ]; then
|
||||||
24
src/entry.sh
24
src/entry.sh
@@ -1,17 +1,17 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
set -Eeuo pipefail
|
set -Eeuo pipefail
|
||||||
|
|
||||||
echo "❯ Starting Virtual DSM for Docker v$(</run/version)..."
|
APP="Virtual DSM"
|
||||||
echo "❯ For support visit https://github.com/vdsm/virtual-dsm/"
|
SUPPORT="https://github.com/vdsm/virtual-dsm"
|
||||||
|
|
||||||
cd /run
|
cd /run
|
||||||
|
|
||||||
. reset.sh # Initialize system
|
. reset.sh # Initialize system
|
||||||
. install.sh # Run installation
|
. install.sh # Run installation
|
||||||
. disk.sh # Initialize disks
|
. disk.sh # Initialize disks
|
||||||
|
. display.sh # Initialize graphics
|
||||||
. network.sh # Initialize network
|
. network.sh # Initialize network
|
||||||
. gpu.sh # Initialize graphics
|
. proc.sh # Initialize processor
|
||||||
. cpu.sh # Initialize processor
|
|
||||||
. serial.sh # Initialize serialport
|
. serial.sh # Initialize serialport
|
||||||
. power.sh # Configure shutdown
|
. power.sh # Configure shutdown
|
||||||
. config.sh # Configure arguments
|
. config.sh # Configure arguments
|
||||||
@@ -19,15 +19,15 @@ cd /run
|
|||||||
trap - ERR
|
trap - ERR
|
||||||
|
|
||||||
if [[ "$CONSOLE" == [Yy]* ]]; then
|
if [[ "$CONSOLE" == [Yy]* ]]; then
|
||||||
exec qemu-system-x86_64 -pidfile "$QEMU_PID" ${ARGS:+ $ARGS}
|
exec qemu-system-x86_64 ${ARGS:+ $ARGS}
|
||||||
exit $?
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
[[ "$DEBUG" == [Yy1]* ]] && info "$VERS" && set -x
|
[[ "$DEBUG" == [Yy1]* ]] && info "$VERS" && echo "Arguments: $ARGS" && echo
|
||||||
qemu-system-x86_64 -daemonize -pidfile "$QEMU_PID" ${ARGS:+ $ARGS}
|
{ qemu-system-x86_64 ${ARGS:+ $ARGS} >"$QEMU_OUT" 2>"$QEMU_LOG"; rc=$?; } || :
|
||||||
|
(( rc != 0 )) && error "$(<"$QEMU_LOG")" && exit 15
|
||||||
|
|
||||||
{ set +x; } 2>/dev/null
|
terminal
|
||||||
cat /dev/pts/1 2>/dev/null & wait $! || true
|
tail -fn +0 "$QEMU_LOG" 2>/dev/null &
|
||||||
|
cat "$QEMU_TERM" 2>/dev/null & wait $! || :
|
||||||
|
|
||||||
sleep 1
|
sleep 1 && finish 0
|
||||||
finish 0
|
|
||||||
|
|||||||
121
src/install.sh
121
src/install.sh
@@ -1,23 +1,29 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
set -Eeuo pipefail
|
set -Eeuo pipefail
|
||||||
|
|
||||||
: ${URL:=''} # URL of the PAT file to be downloaded.
|
: "${URL:=""}" # URL of the PAT file to be downloaded.
|
||||||
|
|
||||||
if [ -f "$STORAGE"/dsm.ver ]; then
|
if [ -f "$STORAGE/dsm.ver" ]; then
|
||||||
BASE=$(cat "$STORAGE/dsm.ver")
|
BASE=$(<"$STORAGE/dsm.ver")
|
||||||
else
|
else
|
||||||
# Fallback for old installs
|
# Fallback for old installs
|
||||||
BASE="DSM_VirtualDSM_42962"
|
BASE="DSM_VirtualDSM_42962"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
[ -n "$URL" ] && BASE=$(basename "$URL" .pat)
|
if [ -n "$URL" ]; then
|
||||||
|
BASE=$(basename "$URL" .pat)
|
||||||
|
if [ ! -f "$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
|
||||||
|
fi
|
||||||
|
|
||||||
if [[ -f "$STORAGE/$BASE.boot.img" ]] && [[ -f "$STORAGE/$BASE.system.img" ]]; then
|
if [[ -f "$STORAGE/$BASE.boot.img" ]] && [[ -f "$STORAGE/$BASE.system.img" ]]; then
|
||||||
return 0 # Previous installation found
|
return 0 # Previous installation found
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Display wait message
|
html "Please wait while Virtual DSM is being installed..."
|
||||||
/run/server.sh 5000 install &
|
|
||||||
|
|
||||||
DL=""
|
DL=""
|
||||||
DL_CHINA="https://cndl.synology.cn/download/DSM"
|
DL_CHINA="https://cndl.synology.cn/download/DSM"
|
||||||
@@ -34,47 +40,55 @@ fi
|
|||||||
|
|
||||||
[ -z "$URL" ] && URL="$DL/release/7.2.1/69057-1/DSM_VirtualDSM_69057.pat"
|
[ -z "$URL" ] && URL="$DL/release/7.2.1/69057-1/DSM_VirtualDSM_69057.pat"
|
||||||
|
|
||||||
BASE=$(basename "$URL" .pat)
|
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
|
if [[ "$URL" != "file://$STORAGE/$BASE.pat" ]]; then
|
||||||
rm -f "$STORAGE"/"$BASE".pat
|
rm -f "$STORAGE/$BASE.pat"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
rm -f "$STORAGE"/"$BASE".agent
|
rm -f "$STORAGE/$BASE.agent"
|
||||||
rm -f "$STORAGE"/"$BASE".boot.img
|
rm -f "$STORAGE/$BASE.boot.img"
|
||||||
rm -f "$STORAGE"/"$BASE".system.img
|
rm -f "$STORAGE/$BASE.system.img"
|
||||||
|
|
||||||
[[ "$DEBUG" == [Yy1]* ]] && set -x
|
[[ "$DEBUG" == [Yy1]* ]] && set -x
|
||||||
|
|
||||||
# Check filesystem
|
# Check filesystem
|
||||||
MIN_ROOT=471859200
|
|
||||||
MIN_SPACE=6442450944
|
|
||||||
FS=$(stat -f -c %T "$STORAGE")
|
FS=$(stat -f -c %T "$STORAGE")
|
||||||
|
|
||||||
if [[ "${FS,,}" == "overlay"* ]]; then
|
if [[ "${FS,,}" == "overlay"* ]]; then
|
||||||
info "Warning: the filesystem of $STORAGE is OverlayFS, this usually means it was binded to an invalid path!"
|
info "Warning: the filesystem of $STORAGE is OverlayFS, this usually means it was binded to an invalid path!"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "${FS,,}" != "fat"* && "${FS,,}" != "vfat"* && "${FS,,}" != "exfat"* && \
|
if [[ "${FS,,}" == "fuse"* ]]; then
|
||||||
"${FS,,}" != "ntfs"* && "${FS,,}" != "fuse"* && "${FS,,}" != "msdos"* ]]; then
|
info "Warning: the filesystem of $STORAGE is FUSE, this extra layer will negatively affect performance!"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "${FS,,}" != "fat"* && "${FS,,}" != "vfat"* && "${FS,,}" != "exfat"* && "${FS,,}" != "ntfs"* && "${FS,,}" != "msdos"* ]]; then
|
||||||
TMP="$STORAGE/tmp"
|
TMP="$STORAGE/tmp"
|
||||||
else
|
else
|
||||||
TMP="/tmp/dsm"
|
TMP="/tmp/dsm"
|
||||||
|
TMP_SPACE=2147483648
|
||||||
SPACE=$(df --output=avail -B 1 /tmp | tail -n 1)
|
SPACE=$(df --output=avail -B 1 /tmp | tail -n 1)
|
||||||
if (( MIN_SPACE > SPACE )); then
|
SPACE_MB=$(( (SPACE + 1048575)/1048576 ))
|
||||||
error "The ${FS^^} filesystem of $STORAGE does not support UNIX permissions, and no space left in container!" && exit 93
|
if (( TMP_SPACE > SPACE )); then
|
||||||
|
error "Not enough free space inside the container, have $SPACE_MB MB available but need at least 2 GB." && exit 93
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
rm -rf "$TMP" && mkdir -p "$TMP"
|
rm -rf "$TMP" && mkdir -p "$TMP"
|
||||||
|
|
||||||
# Check free diskspace
|
# Check free diskspace
|
||||||
|
ROOT_SPACE=536870912
|
||||||
SPACE=$(df --output=avail -B 1 / | tail -n 1)
|
SPACE=$(df --output=avail -B 1 / | tail -n 1)
|
||||||
(( MIN_ROOT > SPACE )) && error "Not enough free space in container root, need at least 450 MB available." && exit 96
|
SPACE_MB=$(( (SPACE + 1048575)/1048576 ))
|
||||||
|
(( ROOT_SPACE > SPACE )) && error "Not enough free space inside the container, have $SPACE_MB MB available but need at least 500 MB." && exit 96
|
||||||
|
|
||||||
|
MIN_SPACE=8589934592
|
||||||
SPACE=$(df --output=avail -B 1 "$STORAGE" | tail -n 1)
|
SPACE=$(df --output=avail -B 1 "$STORAGE" | tail -n 1)
|
||||||
SPACE_GB=$(( (SPACE + 1073741823)/1073741824 ))
|
SPACE_GB=$(( (SPACE + 1073741823)/1073741824 ))
|
||||||
(( MIN_SPACE > SPACE )) && error "Not enough free space for installation in $STORAGE, have $SPACE_GB GB available but need at least 6 GB." && exit 94
|
(( MIN_SPACE > SPACE )) && error "Not enough free space for installation in $STORAGE, have $SPACE_GB GB available but need at least 8 GB." && exit 94
|
||||||
|
|
||||||
# Check if output is to interactive TTY
|
# Check if output is to interactive TTY
|
||||||
if [ -t 1 ]; then
|
if [ -t 1 ]; then
|
||||||
@@ -90,7 +104,8 @@ RDC="$STORAGE/dsm.rd"
|
|||||||
|
|
||||||
if [ ! -f "$RDC" ]; then
|
if [ ! -f "$RDC" ]; then
|
||||||
|
|
||||||
info "Install: Downloading installer..."
|
MSG="Downloading installer..."
|
||||||
|
info "Install: $MSG" && html "$MSG"
|
||||||
|
|
||||||
RD="$TMP/rd.gz"
|
RD="$TMP/rd.gz"
|
||||||
POS="65627648-71021835"
|
POS="65627648-71021835"
|
||||||
@@ -133,7 +148,7 @@ if [ -f "$RDC" ]; then
|
|||||||
(( rc != 0 )) && error "Failed to extract $RDC, reason $rc" && exit 92
|
(( rc != 0 )) && error "Failed to extract $RDC, reason $rc" && exit 92
|
||||||
fi
|
fi
|
||||||
|
|
||||||
mkdir -p /run/extract
|
rm -rf /run/extract && mkdir -p /run/extract
|
||||||
for file in $TMP/usr/lib/libcurl.so.4 \
|
for file in $TMP/usr/lib/libcurl.so.4 \
|
||||||
$TMP/usr/lib/libmbedcrypto.so.5 \
|
$TMP/usr/lib/libmbedcrypto.so.5 \
|
||||||
$TMP/usr/lib/libmbedtls.so.13 \
|
$TMP/usr/lib/libmbedtls.so.13 \
|
||||||
@@ -159,7 +174,8 @@ fi
|
|||||||
|
|
||||||
rm -rf "$TMP" && mkdir -p "$TMP"
|
rm -rf "$TMP" && mkdir -p "$TMP"
|
||||||
|
|
||||||
info "Install: Downloading $(basename "$URL")..."
|
MSG="Downloading $BASE.pat..."
|
||||||
|
info "Install: $MSG" && html "$MSG"
|
||||||
|
|
||||||
PAT="/$BASE.pat"
|
PAT="/$BASE.pat"
|
||||||
rm -f "$PAT"
|
rm -f "$PAT"
|
||||||
@@ -183,7 +199,8 @@ 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
|
||||||
|
|
||||||
info "Install: Extracting downloaded image..."
|
MSG="Extracting downloaded image..."
|
||||||
|
info "Install: $MSG" && html "$MSG"
|
||||||
|
|
||||||
if { tar tf "$PAT"; } >/dev/null 2>&1; then
|
if { tar tf "$PAT"; } >/dev/null 2>&1; then
|
||||||
|
|
||||||
@@ -205,7 +222,10 @@ else
|
|||||||
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
info "Install: Preparing system partition..."
|
rm -rf /run/extract
|
||||||
|
|
||||||
|
MSG="Preparing system partition..."
|
||||||
|
info "Install: $MSG" && html "$MSG"
|
||||||
|
|
||||||
BOOT=$(find "$TMP" -name "*.bin.zip")
|
BOOT=$(find "$TMP" -name "*.bin.zip")
|
||||||
[ ! -f "$BOOT" ] && error "The PAT file contains no boot image." && exit 67
|
[ ! -f "$BOOT" ] && error "The PAT file contains no boot image." && exit 67
|
||||||
@@ -213,19 +233,22 @@ BOOT=$(find "$TMP" -name "*.bin.zip")
|
|||||||
BOOT=$(echo "$BOOT" | head -c -5)
|
BOOT=$(echo "$BOOT" | head -c -5)
|
||||||
unzip -q -o "$BOOT".zip -d "$TMP"
|
unzip -q -o "$BOOT".zip -d "$TMP"
|
||||||
|
|
||||||
SYSTEM="$TMP/sys.img"
|
SYSTEM="$STORAGE/$BASE.system.img"
|
||||||
SYSTEM_SIZE=4954537983
|
|
||||||
rm -f "$SYSTEM"
|
rm -f "$SYSTEM"
|
||||||
|
|
||||||
# Check free diskspace
|
# Check free diskspace
|
||||||
SPACE=$(df --output=avail -B 1 "$TMP" | tail -n 1)
|
SYSTEM_SIZE=4954537983
|
||||||
SPACE_GB=$(( (SPACE + 1073741823)/1073741824 ))
|
SPACE=$(df --output=avail -B 1 "$STORAGE" | tail -n 1)
|
||||||
(( SYSTEM_SIZE > SPACE )) && error "Not enough free space to create a 4 GB system disk, have only $SPACE_GB GB available." && exit 97
|
SPACE_MB=$(( (SPACE + 1048575)/1048576 ))
|
||||||
|
|
||||||
|
if (( SYSTEM_SIZE > SPACE )); then
|
||||||
|
error "Not enough free space in $STORAGE to create a 5 GB system disk, have only $SPACE_MB MB available." && exit 97
|
||||||
|
fi
|
||||||
|
|
||||||
if ! touch "$SYSTEM"; then
|
if ! touch "$SYSTEM"; then
|
||||||
error "Could not create file $SYSTEM for the system disk." && exit 98
|
error "Could not create file $SYSTEM for the system disk." && exit 98
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "${FS,,}" == "xfs" || "${FS,,}" == "zfs" || "${FS,,}" == "btrfs" || "${FS,,}" == "bcachefs" ]]; then
|
if [[ "${FS,,}" == "xfs" || "${FS,,}" == "zfs" || "${FS,,}" == "btrfs" || "${FS,,}" == "bcachefs" ]]; then
|
||||||
{ chattr +C "$SYSTEM"; } || :
|
{ chattr +C "$SYSTEM"; } || :
|
||||||
FA=$(lsattr "$SYSTEM")
|
FA=$(lsattr "$SYSTEM")
|
||||||
@@ -241,17 +264,6 @@ if ! fallocate -l "$SYSTEM_SIZE" "$SYSTEM"; then
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Check if file exists
|
|
||||||
[ ! -f "$SYSTEM" ] && error "System disk does not exist ($SYSTEM)" && exit 99
|
|
||||||
|
|
||||||
# Check the filesize
|
|
||||||
SIZE=$(stat -c%s "$SYSTEM")
|
|
||||||
|
|
||||||
if [[ SIZE -ne SYSTEM_SIZE ]]; then
|
|
||||||
rm -f "$SYSTEM"
|
|
||||||
error "System disk has the wrong size: $SIZE vs $SYSTEM_SIZE" && exit 90
|
|
||||||
fi
|
|
||||||
|
|
||||||
PART="$TMP/partition.fdisk"
|
PART="$TMP/partition.fdisk"
|
||||||
|
|
||||||
{ echo "label: dos"
|
{ echo "label: dos"
|
||||||
@@ -269,7 +281,8 @@ sfdisk -q "$SYSTEM" < "$PART"
|
|||||||
MOUNT="$TMP/system"
|
MOUNT="$TMP/system"
|
||||||
rm -rf "$MOUNT" && mkdir -p "$MOUNT"
|
rm -rf "$MOUNT" && mkdir -p "$MOUNT"
|
||||||
|
|
||||||
info "Install: Extracting system partition..."
|
MSG="Extracting system partition..."
|
||||||
|
info "Install: $MSG" && html "$MSG"
|
||||||
|
|
||||||
HDA="$TMP/hda1"
|
HDA="$TMP/hda1"
|
||||||
IDB="$TMP/indexdb"
|
IDB="$TMP/indexdb"
|
||||||
@@ -277,15 +290,8 @@ PKG="$TMP/packages"
|
|||||||
HDP="$TMP/synohdpack_img"
|
HDP="$TMP/synohdpack_img"
|
||||||
|
|
||||||
[ ! -f "$HDA.tgz" ] && error "The PAT file contains no OS image." && exit 64
|
[ ! -f "$HDA.tgz" ] && error "The PAT file contains no OS image." && exit 64
|
||||||
|
|
||||||
mv "$HDA.tgz" "$HDA.txz"
|
mv "$HDA.tgz" "$HDA.txz"
|
||||||
|
|
||||||
if [[ "$ROOT" != [Nn]* ]]; then
|
|
||||||
|
|
||||||
tar xpfJ "$HDA.txz" --absolute-names -C "$MOUNT/"
|
|
||||||
|
|
||||||
fi
|
|
||||||
|
|
||||||
[ -d "$PKG" ] && mv "$PKG/" "$MOUNT/.SynoUpgradePackages/"
|
[ -d "$PKG" ] && mv "$PKG/" "$MOUNT/.SynoUpgradePackages/"
|
||||||
rm -f "$MOUNT/.SynoUpgradePackages/ActiveInsight-"*
|
rm -f "$MOUNT/.SynoUpgradePackages/ActiveInsight-"*
|
||||||
|
|
||||||
@@ -300,10 +306,13 @@ fi
|
|||||||
LABEL="1.44.1-42218"
|
LABEL="1.44.1-42218"
|
||||||
OFFSET="1048576" # 2048 * 512
|
OFFSET="1048576" # 2048 * 512
|
||||||
NUMBLOCKS="622560" # (4980480 * 512) / 4096
|
NUMBLOCKS="622560" # (4980480 * 512) / 4096
|
||||||
|
MSG="Installing system partition..."
|
||||||
|
|
||||||
if [[ "$ROOT" != [Nn]* ]]; then
|
if [[ "$ROOT" != [Nn]* ]]; then
|
||||||
|
|
||||||
info "Install: Installing system partition..."
|
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"
|
mke2fs -q -t ext4 -b 4096 -d "$MOUNT/" -L "$LABEL" -F -E "offset=$OFFSET" "$SYSTEM" "$NUMBLOCKS"
|
||||||
|
|
||||||
@@ -311,27 +320,25 @@ else
|
|||||||
|
|
||||||
fakeroot -- bash -c "set -Eeu;\
|
fakeroot -- bash -c "set -Eeu;\
|
||||||
tar xpfJ $HDA.txz --absolute-names --skip-old-files -C $MOUNT/;\
|
tar xpfJ $HDA.txz --absolute-names --skip-old-files -C $MOUNT/;\
|
||||||
printf '%b%s%b' '\E[1;34m❯ \E[1;36m' 'Install: Installing system partition...' '\E[0m\n';\
|
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"
|
||||||
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
rm -rf "$MOUNT"
|
rm -rf "$MOUNT"
|
||||||
|
echo "$BASE" > "$STORAGE/dsm.ver"
|
||||||
echo "$BASE" > "$STORAGE"/dsm.ver
|
|
||||||
|
|
||||||
if [[ "$URL" == "file://$STORAGE/$BASE.pat" ]]; then
|
if [[ "$URL" == "file://$STORAGE/$BASE.pat" ]]; then
|
||||||
rm -f "$PAT"
|
rm -f "$PAT"
|
||||||
else
|
else
|
||||||
mv -f "$PAT" "$STORAGE"/"$BASE".pat
|
mv -f "$PAT" "$STORAGE/$BASE.pat"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
mv -f "$BOOT" "$STORAGE"/"$BASE".boot.img
|
mv -f "$BOOT" "$STORAGE/$BASE.boot.img"
|
||||||
mv -f "$SYSTEM" "$STORAGE"/"$BASE".system.img
|
|
||||||
|
|
||||||
rm -rf "$TMP"
|
rm -rf "$TMP"
|
||||||
|
|
||||||
{ set +x; } 2>/dev/null
|
{ set +x; } 2>/dev/null
|
||||||
[[ "$DEBUG" == [Yy1]* ]] && echo
|
[[ "$DEBUG" == [Yy1]* ]] && echo
|
||||||
|
|
||||||
|
html "Installation finished successfully..."
|
||||||
return 0
|
return 0
|
||||||
|
|||||||
129
src/network.sh
129
src/network.sh
@@ -3,17 +3,17 @@ set -Eeuo pipefail
|
|||||||
|
|
||||||
# Docker environment variables
|
# Docker environment variables
|
||||||
|
|
||||||
: ${DHCP:='N'}
|
: "${DHCP:="N"}"
|
||||||
: ${MAC:='02:11:32:AA:BB:CC'}
|
: "${MAC:="02:11:32:AA:BB:CC"}"
|
||||||
|
|
||||||
: ${VM_NET_TAP:='dsm'}
|
: "${VM_NET_DEV:=""}"
|
||||||
: ${VM_NET_DEV:='eth0'}
|
: "${VM_NET_TAP:="dsm"}"
|
||||||
: ${VM_NET_MAC:="$MAC"}
|
: "${VM_NET_MAC:="$MAC"}"
|
||||||
: ${VM_NET_HOST:='VirtualDSM'}
|
: "${VM_NET_HOST:="VirtualDSM"}"
|
||||||
|
|
||||||
: ${DNSMASQ_OPTS:=''}
|
: "${DNSMASQ_OPTS:=""}"
|
||||||
: ${DNSMASQ:='/usr/sbin/dnsmasq'}
|
: "${DNSMASQ:="/usr/sbin/dnsmasq"}"
|
||||||
: ${DNSMASQ_CONF_DIR:='/etc/dnsmasq.d'}
|
: "${DNSMASQ_CONF_DIR:="/etc/dnsmasq.d"}"
|
||||||
|
|
||||||
ADD_ERR="Please add the following setting to your container:"
|
ADD_ERR="Please add the following setting to your container:"
|
||||||
|
|
||||||
@@ -69,7 +69,7 @@ configureDHCP() {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
configureDNS () {
|
configureDNS() {
|
||||||
|
|
||||||
# dnsmasq configuration:
|
# dnsmasq configuration:
|
||||||
DNSMASQ_OPTS="$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"
|
DNSMASQ_OPTS="$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"
|
||||||
@@ -90,7 +90,27 @@ configureDNS () {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
configureNAT () {
|
configureNAT() {
|
||||||
|
|
||||||
|
# Create the necessary file structure for /dev/net/tun
|
||||||
|
if [ ! -c /dev/net/tun ]; then
|
||||||
|
[ ! -d /dev/net ] && mkdir -m 755 /dev/net
|
||||||
|
if mknod /dev/net/tun c 10 200; then
|
||||||
|
chmod 666 /dev/net/tun
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -c /dev/net/tun ]; then
|
||||||
|
error "TUN device missing. $ADD_ERR --cap-add NET_ADMIN" && exit 25
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check port forwarding flag
|
||||||
|
if [[ $(< /proc/sys/net/ipv4/ip_forward) -eq 0 ]]; then
|
||||||
|
{ sysctl -w net.ipv4.ip_forward=1 ; rc=$?; } || :
|
||||||
|
if (( rc != 0 )); then
|
||||||
|
error "IP forwarding is disabled. $ADD_ERR --sysctl net.ipv4.ip_forward=1" && exit 24
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
# Create a bridge with a static IP for the VM guest
|
# Create a bridge with a static IP for the VM guest
|
||||||
|
|
||||||
@@ -121,8 +141,11 @@ configureNAT () {
|
|||||||
ip link set dev "$VM_NET_TAP" master dockerbridge
|
ip link set dev "$VM_NET_TAP" master dockerbridge
|
||||||
|
|
||||||
# Add internet connection to the VM
|
# Add internet connection to the VM
|
||||||
|
update-alternatives --set iptables /usr/sbin/iptables-legacy > /dev/null
|
||||||
|
update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy > /dev/null
|
||||||
|
|
||||||
iptables -t nat -A POSTROUTING -o "$VM_NET_DEV" -j MASQUERADE
|
iptables -t nat -A POSTROUTING -o "$VM_NET_DEV" -j MASQUERADE
|
||||||
iptables -t nat -A PREROUTING -i "$VM_NET_DEV" -d "$IP" -p tcp -j DNAT --to "$VM_NET_IP"
|
iptables -t nat -A PREROUTING -i "$VM_NET_DEV" -d "$IP" -p tcp -j DNAT --to "$VM_NET_IP"
|
||||||
iptables -t nat -A PREROUTING -i "$VM_NET_DEV" -d "$IP" -p udp -j DNAT --to "$VM_NET_IP"
|
iptables -t nat -A PREROUTING -i "$VM_NET_DEV" -d "$IP" -p udp -j DNAT --to "$VM_NET_IP"
|
||||||
|
|
||||||
if (( KERNEL > 4 )); then
|
if (( KERNEL > 4 )); then
|
||||||
@@ -133,14 +156,6 @@ configureNAT () {
|
|||||||
{ set +x; } 2>/dev/null
|
{ set +x; } 2>/dev/null
|
||||||
[[ "$DEBUG" == [Yy1]* ]] && echo
|
[[ "$DEBUG" == [Yy1]* ]] && echo
|
||||||
|
|
||||||
# Check port forwarding flag
|
|
||||||
if [[ $(< /proc/sys/net/ipv4/ip_forward) -eq 0 ]]; then
|
|
||||||
{ sysctl -w net.ipv4.ip_forward=1 ; rc=$?; } || :
|
|
||||||
if (( rc != 0 )); then
|
|
||||||
error "IP forwarding is disabled. $ADD_ERR --sysctl net.ipv4.ip_forward=1" && exit 24
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
NET_OPTS="-netdev tap,ifname=$VM_NET_TAP,script=no,downscript=no,id=hostnet0"
|
NET_OPTS="-netdev tap,ifname=$VM_NET_TAP,script=no,downscript=no,id=hostnet0"
|
||||||
|
|
||||||
{ exec 40>>/dev/vhost-net; rc=$?; } 2>/dev/null || :
|
{ exec 40>>/dev/vhost-net; rc=$?; } 2>/dev/null || :
|
||||||
@@ -151,21 +166,24 @@ configureNAT () {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
closeNetwork () {
|
closeNetwork() {
|
||||||
|
|
||||||
exec 30<&- || true
|
exec 30<&- || true
|
||||||
exec 40<&- || true
|
exec 40<&- || true
|
||||||
|
|
||||||
if [[ "$DHCP" == [Yy1]* ]]; then
|
if [[ "$DHCP" == [Yy1]* ]]; then
|
||||||
|
|
||||||
fKill "server.sh"
|
# Shutdown nginx
|
||||||
|
nginx -s stop 2> /dev/null
|
||||||
|
fWait "nginx"
|
||||||
|
|
||||||
ip link set "$VM_NET_TAP" down || true
|
ip link set "$VM_NET_TAP" down || true
|
||||||
ip link delete "$VM_NET_TAP" || true
|
ip link delete "$VM_NET_TAP" || true
|
||||||
|
|
||||||
else
|
else
|
||||||
|
|
||||||
fKill "dnsmasq"
|
local pid="/var/run/dnsmasq.pid"
|
||||||
|
[ -f "$pid" ] && pKill "$(<"$pid")"
|
||||||
|
|
||||||
ip link set "$VM_NET_TAP" down promisc off || true
|
ip link set "$VM_NET_TAP" down promisc off || true
|
||||||
ip link delete "$VM_NET_TAP" || true
|
ip link delete "$VM_NET_TAP" || true
|
||||||
@@ -174,42 +192,55 @@ closeNetwork () {
|
|||||||
ip link delete dockerbridge || true
|
ip link delete dockerbridge || true
|
||||||
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
getInfo() {
|
||||||
|
|
||||||
|
if [ -z "$VM_NET_DEV" ]; then
|
||||||
|
# Automaticly detect the default network interface
|
||||||
|
VM_NET_DEV=$(awk '$2 == 00000000 { print $1 }' /proc/net/route)
|
||||||
|
[ -z "$VM_NET_DEV" ] && VM_NET_DEV="eth0"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -d "/sys/class/net/$VM_NET_DEV" ]; then
|
||||||
|
error "Network interface '$VM_NET_DEV' does not exist inside the container!"
|
||||||
|
error "$ADD_ERR -e \"VM_NET_DEV=NAME\" to specify another interface name." && exit 27
|
||||||
|
fi
|
||||||
|
|
||||||
|
VM_NET_MAC="${VM_NET_MAC//-/:}"
|
||||||
|
if [[ ${#VM_NET_MAC} == 12 ]]; then
|
||||||
|
m="$VM_NET_MAC"
|
||||||
|
VM_NET_MAC="${m:0:2}:${m:2:2}:${m:4:2}:${m:6:2}:${m:8:2}:${m:10:2}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ${#VM_NET_MAC} != 17 ]]; then
|
||||||
|
error "Invalid mac address: '$VM_NET_MAC', should be 12 or 17 digits long!" && exit 28
|
||||||
|
fi
|
||||||
|
|
||||||
|
GATEWAY=$(ip r | grep default | awk '{print $3}')
|
||||||
|
IP=$(ip address show dev "$VM_NET_DEV" | grep inet | awk '/inet / { print $2 }' | cut -f1 -d/)
|
||||||
|
echo "$IP" > /run/shm/qemu.ip
|
||||||
|
|
||||||
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
# ######################################
|
# ######################################
|
||||||
# Configure Network
|
# Configure Network
|
||||||
# ######################################
|
# ######################################
|
||||||
|
|
||||||
fKill "server.sh"
|
|
||||||
|
|
||||||
# Create the necessary file structure for /dev/net/tun
|
|
||||||
if [ ! -c /dev/net/tun ]; then
|
|
||||||
[ ! -d /dev/net ] && mkdir -m 755 /dev/net
|
|
||||||
if mknod /dev/net/tun c 10 200; then
|
|
||||||
chmod 666 /dev/net/tun
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ ! -c /dev/net/tun ]; then
|
|
||||||
error "TUN device missing. $ADD_ERR --cap-add NET_ADMIN" && exit 25
|
|
||||||
fi
|
|
||||||
|
|
||||||
# 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
|
||||||
chmod 660 /dev/vhost-net
|
chmod 660 /dev/vhost-net
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
update-alternatives --set iptables /usr/sbin/iptables-legacy > /dev/null
|
getInfo
|
||||||
update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy > /dev/null
|
html "Initializing network..."
|
||||||
|
|
||||||
VM_NET_MAC="${VM_NET_MAC//-/:}"
|
|
||||||
GATEWAY=$(ip r | grep default | awk '{print $3}')
|
|
||||||
IP=$(ip address show dev "$VM_NET_DEV" | grep inet | awk '/inet / { print $2 }' | cut -f1 -d/)
|
|
||||||
|
|
||||||
if [[ "$DEBUG" == [Yy1]* ]]; then
|
if [[ "$DEBUG" == [Yy1]* ]]; then
|
||||||
info "Container IP is $IP with gateway $GATEWAY" && echo
|
info "Container IP is $IP with gateway $GATEWAY on interface $VM_NET_DEV" && echo
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "$DHCP" == [Yy1]* ]]; then
|
if [[ "$DHCP" == [Yy1]* ]]; then
|
||||||
@@ -223,11 +254,15 @@ if [[ "$DHCP" == [Yy1]* ]]; then
|
|||||||
# Configuration for DHCP IP
|
# Configuration for DHCP IP
|
||||||
configureDHCP
|
configureDHCP
|
||||||
|
|
||||||
# Display IP on port 80 and 5000
|
MSG="Please wait while discovering IP..."
|
||||||
/run/server.sh 5000 /run/ip.sh &
|
html "$MSG" "2000"
|
||||||
|
|
||||||
else
|
else
|
||||||
|
|
||||||
|
# Shutdown nginx
|
||||||
|
nginx -s stop 2> /dev/null
|
||||||
|
fWait "nginx"
|
||||||
|
|
||||||
# Configuration for static IP
|
# Configuration for static IP
|
||||||
configureNAT
|
configureNAT
|
||||||
|
|
||||||
|
|||||||
96
src/power.sh
96
src/power.sh
@@ -7,18 +7,20 @@ API_CMD=6
|
|||||||
API_TIMEOUT=50
|
API_TIMEOUT=50
|
||||||
API_HOST="127.0.0.1:2210"
|
API_HOST="127.0.0.1:2210"
|
||||||
|
|
||||||
|
QEMU_TERM=""
|
||||||
QEMU_PORT=7100
|
QEMU_PORT=7100
|
||||||
QEMU_TIMEOUT=50
|
QEMU_TIMEOUT=50
|
||||||
QEMU_PID="/run/qemu.pid"
|
QEMU_PID="/run/shm/qemu.pid"
|
||||||
QEMU_COUNT="/run/qemu.count"
|
QEMU_LOG="/run/shm/qemu.log"
|
||||||
|
QEMU_OUT="/run/shm/qemu.out"
|
||||||
|
QEMU_END="/run/shm/qemu.end"
|
||||||
|
|
||||||
if [[ "$KVM" == [Nn]* ]]; then
|
if [[ "$KVM" == [Nn]* ]]; then
|
||||||
API_TIMEOUT=$(( API_TIMEOUT*2 ))
|
API_TIMEOUT=$(( API_TIMEOUT*2 ))
|
||||||
QEMU_TIMEOUT=$(( QEMU_TIMEOUT*2 ))
|
QEMU_TIMEOUT=$(( QEMU_TIMEOUT*2 ))
|
||||||
fi
|
fi
|
||||||
|
|
||||||
rm -f "$QEMU_PID"
|
touch "$QEMU_LOG"
|
||||||
rm -f "$QEMU_COUNT"
|
|
||||||
|
|
||||||
_trap() {
|
_trap() {
|
||||||
func="$1" ; shift
|
func="$1" ; shift
|
||||||
@@ -34,8 +36,8 @@ finish() {
|
|||||||
|
|
||||||
if [ -f "$QEMU_PID" ]; then
|
if [ -f "$QEMU_PID" ]; then
|
||||||
|
|
||||||
pid="$(cat "$QEMU_PID")"
|
pid=$(<"$QEMU_PID")
|
||||||
echo && error "Forcefully quitting QEMU process, reason: $reason..."
|
echo && error "Forcefully terminating QEMU process, reason: $reason..."
|
||||||
{ kill -15 "$pid" || true; } 2>/dev/null
|
{ kill -15 "$pid" || true; } 2>/dev/null
|
||||||
|
|
||||||
while isAlive "$pid"; do
|
while isAlive "$pid"; do
|
||||||
@@ -51,20 +53,63 @@ finish() {
|
|||||||
closeNetwork
|
closeNetwork
|
||||||
|
|
||||||
sleep 1
|
sleep 1
|
||||||
echo && info "Shutdown completed!"
|
echo && echo "❯ Shutdown completed!"
|
||||||
|
|
||||||
exit "$reason"
|
exit "$reason"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
terminal() {
|
||||||
|
|
||||||
|
local dev=""
|
||||||
|
|
||||||
|
if [ -f "$QEMU_OUT" ]; then
|
||||||
|
|
||||||
|
local msg
|
||||||
|
msg=$(<"$QEMU_OUT")
|
||||||
|
|
||||||
|
if [ -n "$msg" ]; then
|
||||||
|
|
||||||
|
if [[ "${msg,,}" != "char"* || "$msg" != *"serial0)" ]]; then
|
||||||
|
echo "$msg"
|
||||||
|
fi
|
||||||
|
|
||||||
|
dev="${msg#*/dev/p}"
|
||||||
|
dev="/dev/p${dev%% *}"
|
||||||
|
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -c "$dev" ]; then
|
||||||
|
dev=$(echo 'info chardev' | nc -q 1 -w 1 localhost "$QEMU_PORT" | tr -d '\000')
|
||||||
|
dev="${dev#*serial0}"
|
||||||
|
dev="${dev#*pty:}"
|
||||||
|
dev="${dev%%$'\n'*}"
|
||||||
|
dev="${dev%%$'\r'*}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -c "$dev" ]; then
|
||||||
|
error "Device '$dev' not found!"
|
||||||
|
finish 34 && return 34
|
||||||
|
fi
|
||||||
|
|
||||||
|
QEMU_TERM="$dev"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
_graceful_shutdown() {
|
_graceful_shutdown() {
|
||||||
|
|
||||||
|
local cnt=0
|
||||||
local code=$?
|
local code=$?
|
||||||
local pid cnt response
|
local pid url response
|
||||||
|
|
||||||
[ -f "$QEMU_COUNT" ] && return
|
|
||||||
echo 0 > "$QEMU_COUNT"
|
|
||||||
|
|
||||||
set +e
|
set +e
|
||||||
|
|
||||||
|
if [ -f "$QEMU_END" ]; then
|
||||||
|
echo && info "Received $1 signal while already shutting down..."
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
touch "$QEMU_END"
|
||||||
echo && info "Received $1 signal, sending shutdown command..."
|
echo && info "Received $1 signal, sending shutdown command..."
|
||||||
|
|
||||||
if [ ! -f "$QEMU_PID" ]; then
|
if [ ! -f "$QEMU_PID" ]; then
|
||||||
@@ -72,7 +117,7 @@ _graceful_shutdown() {
|
|||||||
finish "$code" && return "$code"
|
finish "$code" && return "$code"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
pid="$(cat "$QEMU_PID")"
|
pid=$(<"$QEMU_PID")
|
||||||
|
|
||||||
if ! isAlive "$pid"; then
|
if ! isAlive "$pid"; then
|
||||||
echo && error "QEMU process does not exist?"
|
echo && error "QEMU process does not exist?"
|
||||||
@@ -94,20 +139,17 @@ _graceful_shutdown() {
|
|||||||
|
|
||||||
response="${response#*message\"\: \"}"
|
response="${response#*message\"\: \"}"
|
||||||
[ -z "$response" ] && response="second signal"
|
[ -z "$response" ] && response="second signal"
|
||||||
echo && error "Forcefully quitting because of: ${response%%\"*}"
|
echo && error "Forcefully terminating because of: ${response%%\"*}"
|
||||||
{ kill -15 "$pid" || true; } 2>/dev/null
|
{ kill -15 "$pid" || true; } 2>/dev/null
|
||||||
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
while [ "$(cat $QEMU_COUNT)" -lt "$QEMU_TIMEOUT" ]; do
|
while [ "$cnt" -lt "$QEMU_TIMEOUT" ]; do
|
||||||
|
|
||||||
! isAlive "$pid" && break
|
! isAlive "$pid" && break
|
||||||
|
|
||||||
sleep 1
|
sleep 1
|
||||||
|
cnt=$((cnt+1))
|
||||||
# Increase the counter
|
|
||||||
cnt=$(($(cat $QEMU_COUNT)+1))
|
|
||||||
echo $cnt > "$QEMU_COUNT"
|
|
||||||
|
|
||||||
[[ "$DEBUG" == [Yy1]* ]] && info "Shutting down, waiting... ($cnt/$QEMU_TIMEOUT)"
|
[[ "$DEBUG" == [Yy1]* ]] && info "Shutting down, waiting... ($cnt/$QEMU_TIMEOUT)"
|
||||||
|
|
||||||
@@ -116,13 +158,23 @@ _graceful_shutdown() {
|
|||||||
|
|
||||||
done
|
done
|
||||||
|
|
||||||
if [ "$(cat $QEMU_COUNT)" -ge "$QEMU_TIMEOUT" ]; then
|
if [ "$cnt" -ge "$QEMU_TIMEOUT" ]; then
|
||||||
echo && error "Shutdown timeout reached!"
|
echo && error "Shutdown timeout reached, aborting..."
|
||||||
fi
|
fi
|
||||||
|
|
||||||
finish "$code" && return "$code"
|
finish "$code" && return "$code"
|
||||||
}
|
}
|
||||||
|
|
||||||
_trap _graceful_shutdown SIGTERM SIGHUP SIGINT SIGABRT SIGQUIT
|
MON_OPTS="\
|
||||||
|
-pidfile $QEMU_PID \
|
||||||
|
-monitor telnet:localhost:$QEMU_PORT,server,nowait,nodelay"
|
||||||
|
|
||||||
MON_OPTS="-monitor telnet:localhost:$QEMU_PORT,server,nowait,nodelay"
|
if [[ "$CONSOLE" != [Yy]* ]]; then
|
||||||
|
|
||||||
|
MON_OPTS="$MON_OPTS -daemonize -D $QEMU_LOG"
|
||||||
|
|
||||||
|
_trap _graceful_shutdown SIGTERM SIGHUP SIGINT SIGABRT SIGQUIT
|
||||||
|
|
||||||
|
fi
|
||||||
|
|
||||||
|
return 0
|
||||||
|
|||||||
29
src/print.sh
29
src/print.sh
@@ -1,17 +1,20 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
set -Eeuo pipefail
|
set -Eeuo pipefail
|
||||||
|
|
||||||
: ${DHCP:='N'}
|
: "${DHCP:="N"}"
|
||||||
: ${VM_NET_DEV:='eth0'}
|
|
||||||
|
|
||||||
info () { printf "%b%s%b" "\E[1;34m❯ \E[1;36m" "$1" "\E[0m\n" >&2; }
|
info () { printf "%b%s%b" "\E[1;34m❯ \E[1;36m" "$1" "\E[0m\n" >&2; }
|
||||||
error () { printf "%b%s%b" "\E[1;31m❯ " "ERROR: $1" "\E[0m\n" >&2; }
|
error () { printf "%b%s%b" "\E[1;31m❯ " "ERROR: $1" "\E[0m\n" >&2; }
|
||||||
|
|
||||||
file="/run/dsm.url"
|
file="/run/shm/dsm.url"
|
||||||
shutdown="/run/qemu.count"
|
page="/run/shm/index.html"
|
||||||
|
address="/run/shm/qemu.ip"
|
||||||
|
shutdown="/run/shm/qemu.end"
|
||||||
|
template="/var/www/index.html"
|
||||||
url="http://127.0.0.1:2210/read?command=10"
|
url="http://127.0.0.1:2210/read?command=10"
|
||||||
|
|
||||||
resp_err="Guest returned an invalid response:"
|
resp_err="Guest returned an invalid response:"
|
||||||
|
curl_err="Failed to connect to guest: curl error"
|
||||||
jq_err="Failed to parse response from guest: jq error"
|
jq_err="Failed to parse response from guest: jq error"
|
||||||
|
|
||||||
while [ ! -f "$file" ]
|
while [ ! -f "$file" ]
|
||||||
@@ -29,7 +32,7 @@ do
|
|||||||
{ json=$(curl -m 20 -sk "$url"); rc=$?; } || :
|
{ json=$(curl -m 20 -sk "$url"); rc=$?; } || :
|
||||||
|
|
||||||
[ -f "$shutdown" ] && exit 1
|
[ -f "$shutdown" ] && exit 1
|
||||||
(( rc != 0 )) && error "Failed to connect to guest: curl error $rc" && continue
|
(( rc != 0 )) && error "$curl_err $rc" && continue
|
||||||
|
|
||||||
{ result=$(echo "$json" | jq -r '.status'); rc=$?; } || :
|
{ result=$(echo "$json" | jq -r '.status'); rc=$?; } || :
|
||||||
(( rc != 0 )) && error "$jq_err $rc ( $json )" && continue
|
(( rc != 0 )) && error "$jq_err $rc ( $json )" && continue
|
||||||
@@ -60,15 +63,27 @@ done
|
|||||||
|
|
||||||
[ -f "$shutdown" ] && exit 1
|
[ -f "$shutdown" ] && exit 1
|
||||||
|
|
||||||
location=$(cat "$file")
|
location=$(<"$file")
|
||||||
|
|
||||||
if [[ "$location" != "20.20"* ]]; then
|
if [[ "$location" != "20.20"* ]]; then
|
||||||
|
|
||||||
msg="http://$location"
|
msg="http://$location"
|
||||||
|
title="<title>Virtual DSM</title>"
|
||||||
|
body="The location of DSM is <a href='http://$location'>http://$location</a>"
|
||||||
|
script="<script>setTimeout(function(){ window.location.assign('http://$location'); }, 3000);</script>"
|
||||||
|
|
||||||
|
HTML=$(<"$template")
|
||||||
|
HTML="${HTML/\[1\]/$title}"
|
||||||
|
HTML="${HTML/\[2\]/$script}"
|
||||||
|
HTML="${HTML/\[3\]/$body}"
|
||||||
|
HTML="${HTML/\[4\]/}"
|
||||||
|
HTML="${HTML/\[5\]/}"
|
||||||
|
|
||||||
|
echo "$HTML" > "$page"
|
||||||
|
|
||||||
else
|
else
|
||||||
|
|
||||||
ip=$(ip address show dev "$VM_NET_DEV" | grep inet | awk '/inet / { print $2 }' | cut -f1 -d/)
|
ip=$(<"$address")
|
||||||
port="${location##*:}"
|
port="${location##*:}"
|
||||||
|
|
||||||
if [[ "$ip" == "172."* ]]; then
|
if [[ "$ip" == "172."* ]]; then
|
||||||
|
|||||||
@@ -3,9 +3,10 @@ set -Eeuo pipefail
|
|||||||
|
|
||||||
# Docker environment variables
|
# Docker environment variables
|
||||||
|
|
||||||
: ${HOST_CPU:=''}
|
: "${KVM:="Y"}"
|
||||||
: ${CPU_MODEL:='host'}
|
: "${HOST_CPU:=""}"
|
||||||
: ${CPU_FEATURES:='+ssse3,+sse4.1,+sse4.2'}
|
: "${CPU_MODEL:="host"}"
|
||||||
|
: "${CPU_FEATURES:="+ssse3,+sse4.1,+sse4.2"}"
|
||||||
|
|
||||||
[ "$ARCH" != "amd64" ] && KVM="N"
|
[ "$ARCH" != "amd64" ] && KVM="N"
|
||||||
|
|
||||||
@@ -13,12 +14,16 @@ if [[ "$KVM" != [Nn]* ]]; then
|
|||||||
|
|
||||||
KVM_ERR=""
|
KVM_ERR=""
|
||||||
|
|
||||||
if [ -e /dev/kvm ] && sh -c 'echo -n > /dev/kvm' &> /dev/null; then
|
if [ ! -e /dev/kvm ]; then
|
||||||
if ! grep -q -e vmx -e svm /proc/cpuinfo; then
|
KVM_ERR="(device file missing)"
|
||||||
KVM_ERR="(vmx/svm disabled)"
|
|
||||||
fi
|
|
||||||
else
|
else
|
||||||
[ -e /dev/kvm ] && KVM_ERR="(no write access)" || KVM_ERR="(device file missing)"
|
if ! sh -c 'echo -n > /dev/kvm' &> /dev/null; then
|
||||||
|
KVM_ERR="(no write access)"
|
||||||
|
else
|
||||||
|
if ! grep -q -e vmx -e svm /proc/cpuinfo; then
|
||||||
|
KVM_ERR="(vmx/svm disabled)"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -n "$KVM_ERR" ]; then
|
if [ -n "$KVM_ERR" ]; then
|
||||||
136
src/reset.sh
136
src/reset.sh
@@ -3,28 +3,37 @@ set -Eeuo pipefail
|
|||||||
|
|
||||||
info () { printf "%b%s%b" "\E[1;34m❯ \E[1;36m" "$1" "\E[0m\n"; }
|
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; }
|
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
|
||||||
|
|
||||||
[ ! -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
|
||||||
|
|
||||||
|
echo "❯ Starting $APP for Docker v$(</run/version)..."
|
||||||
|
echo "❯ For support visit $SUPPORT"
|
||||||
|
echo
|
||||||
|
|
||||||
# Docker environment variables
|
# Docker environment variables
|
||||||
|
|
||||||
: ${TZ:=''} # System local timezone
|
: "${TZ:=""}" # System local timezone
|
||||||
: ${GPU:='N'} # Disable GPU passthrough
|
: "${DEBUG:="N"}" # Disable debugging mode
|
||||||
: ${KVM:='Y'} # Enable KVM acceleration
|
: "${COUNTRY:=""}" # Country code for mirror
|
||||||
: ${DEBUG:='N'} # Disable debugging mode
|
: "${CONSOLE:="N"}" # Disable console mode
|
||||||
: ${COUNTRY:=''} # Country code for mirror
|
: "${ALLOCATE:=""}" # Preallocate diskspace
|
||||||
: ${CONSOLE:='N'} # Disable console mode
|
: "${ARGUMENTS:=""}" # Extra QEMU parameters
|
||||||
: ${ALLOCATE:='Y'} # Preallocate diskspace
|
: "${CPU_CORES:="1"}" # Amount of CPU cores
|
||||||
: ${ARGUMENTS:=''} # Extra QEMU parameters
|
: "${RAM_SIZE:="1G"}" # Maximum RAM amount
|
||||||
: ${CPU_CORES:='1'} # Amount of CPU cores
|
: "${DISK_SIZE:="16G"}" # Initial data disk size
|
||||||
: ${RAM_SIZE:='1G'} # Maximum RAM amount
|
|
||||||
: ${DISK_SIZE:='16G'} # Initial data disk size
|
|
||||||
|
|
||||||
# Helper variables
|
# Helper variables
|
||||||
|
|
||||||
|
STORAGE="/storage"
|
||||||
|
PAGE="/run/shm/index.html"
|
||||||
|
TEMPLATE="/var/www/index.html"
|
||||||
|
FOOTER1="$APP for Docker v$(</run/version)"
|
||||||
|
FOOTER2="<a href='$SUPPORT'>$SUPPORT</a>"
|
||||||
|
|
||||||
KERNEL=$(uname -r | cut -b 1)
|
KERNEL=$(uname -r | cut -b 1)
|
||||||
MINOR=$(uname -r | cut -d '.' -f2)
|
MINOR=$(uname -r | cut -d '.' -f2)
|
||||||
ARCH=$(dpkg --print-architecture)
|
ARCH=$(dpkg --print-architecture)
|
||||||
@@ -32,19 +41,24 @@ VERS=$(qemu-system-x86_64 --version | head -n 1 | cut -d '(' -f 1)
|
|||||||
|
|
||||||
# Check folder
|
# Check folder
|
||||||
|
|
||||||
STORAGE="/storage"
|
if [ ! -d "$STORAGE" ]; then
|
||||||
[ ! -d "$STORAGE" ] && error "Storage folder ($STORAGE) not found!" && exit 13
|
error "Storage folder ($STORAGE) not found!" && exit 13
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -d "/run/shm" ]; then
|
||||||
|
if [ -d "/dev/shm" ]; then
|
||||||
|
ln -s /dev/shm /run/shm
|
||||||
|
else
|
||||||
|
error "Folder /dev/shm not found!" && exit 14
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
# Cleanup files
|
# Cleanup files
|
||||||
|
rm -f /run/shm/qemu.*
|
||||||
rm -f /run/dsm.url
|
rm -f /run/shm/dsm.url
|
||||||
rm -f /run/qemu.pid
|
|
||||||
rm -f /run/qemu.count
|
|
||||||
|
|
||||||
# Cleanup dirs
|
# Cleanup dirs
|
||||||
|
|
||||||
rm -rf /tmp/dsm
|
rm -rf /tmp/dsm
|
||||||
rm -f /tmp/server.*
|
|
||||||
rm -rf "$STORAGE/tmp"
|
rm -rf "$STORAGE/tmp"
|
||||||
|
|
||||||
# Helper functions
|
# Helper functions
|
||||||
@@ -65,25 +79,75 @@ pKill() {
|
|||||||
{ kill -15 "$pid" || true; } 2>/dev/null
|
{ kill -15 "$pid" || true; } 2>/dev/null
|
||||||
|
|
||||||
while isAlive "$pid"; do
|
while isAlive "$pid"; do
|
||||||
sleep 0.1
|
sleep 0.2
|
||||||
done
|
done
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
fKill () {
|
fWait() {
|
||||||
|
local name=$1
|
||||||
|
|
||||||
|
while pgrep -f -l "$name" >/dev/null; do
|
||||||
|
sleep 0.2
|
||||||
|
done
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
fKill() {
|
||||||
local name=$1
|
local name=$1
|
||||||
|
|
||||||
{ pkill -f "$name" || true; } 2>/dev/null
|
{ pkill -f "$name" || true; } 2>/dev/null
|
||||||
|
fWait "$name"
|
||||||
while pgrep -f -l "$name" >/dev/null; do
|
|
||||||
sleep 0.1
|
|
||||||
done
|
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
getCountry () {
|
escape () {
|
||||||
|
local s
|
||||||
|
s=${1//&/\&}
|
||||||
|
s=${s//</\<}
|
||||||
|
s=${s//>/\>}
|
||||||
|
s=${s//'"'/\"}
|
||||||
|
printf -- %s "$s"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
html()
|
||||||
|
{
|
||||||
|
local title
|
||||||
|
local body
|
||||||
|
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
|
||||||
|
|
||||||
|
local timeout="4999"
|
||||||
|
[ -n "${2:-}" ] && timeout="$2"
|
||||||
|
local script="<script>setTimeout(() => { document.location.reload(); }, $timeout);</script>"
|
||||||
|
[[ "$timeout" == "0" ]] && 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"
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
getCountry() {
|
||||||
local url=$1
|
local url=$1
|
||||||
local query=$2
|
local query=$2
|
||||||
local rc json result
|
local rc json result
|
||||||
@@ -102,7 +166,7 @@ getCountry () {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
setCountry () {
|
setCountry() {
|
||||||
|
|
||||||
[[ "${TZ,,}" == "asia/harbin" ]] && COUNTRY="CN"
|
[[ "${TZ,,}" == "asia/harbin" ]] && COUNTRY="CN"
|
||||||
[[ "${TZ,,}" == "asia/beijing" ]] && COUNTRY="CN"
|
[[ "${TZ,,}" == "asia/beijing" ]] && COUNTRY="CN"
|
||||||
@@ -113,13 +177,14 @@ setCountry () {
|
|||||||
|
|
||||||
[ -z "$COUNTRY" ] && getCountry "https://api.ipapi.is" ".location.country_code"
|
[ -z "$COUNTRY" ] && getCountry "https://api.ipapi.is" ".location.country_code"
|
||||||
[ -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://ipinfo.io/json" ".country"
|
[ -z "$COUNTRY" ] && getCountry "https://ipinfo.io/json" ".country"
|
||||||
[ -z "$COUNTRY" ] && getCountry "https://api.myip.com" ".cc"
|
[ -z "$COUNTRY" ] && getCountry "https://api.myip.com" ".cc"
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
addPackage () {
|
addPackage() {
|
||||||
local pkg=$1
|
local pkg=$1
|
||||||
local desc=$2
|
local desc=$2
|
||||||
|
|
||||||
@@ -127,10 +192,8 @@ addPackage () {
|
|||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
info "Installing $desc..."
|
MSG="Installing $desc..."
|
||||||
|
info "$MSG" && html "$MSG"
|
||||||
export DEBCONF_NOWARNINGS="yes"
|
|
||||||
export DEBIAN_FRONTEND="noninteractive"
|
|
||||||
|
|
||||||
[ -z "$COUNTRY" ] && setCountry
|
[ -z "$COUNTRY" ] && setCountry
|
||||||
|
|
||||||
@@ -138,10 +201,15 @@ addPackage () {
|
|||||||
sed -i 's/deb.debian.org/mirrors.ustc.edu.cn/g' /etc/apt/sources.list.d/debian.sources
|
sed -i 's/deb.debian.org/mirrors.ustc.edu.cn/g' /etc/apt/sources.list.d/debian.sources
|
||||||
fi
|
fi
|
||||||
|
|
||||||
apt-get -qq update
|
DEBIAN_FRONTEND=noninteractive apt-get -qq update
|
||||||
apt-get -qq --no-install-recommends -y install "$pkg" > /dev/null
|
DEBIAN_FRONTEND=noninteractive apt-get -qq --no-install-recommends -y install "$pkg" > /dev/null
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Start webserver
|
||||||
|
cp -r /var/www/* /run/shm
|
||||||
|
html "Starting $APP for Docker..."
|
||||||
|
nginx -e stderr
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
|
|||||||
@@ -3,11 +3,11 @@ set -Eeuo pipefail
|
|||||||
|
|
||||||
# Docker environment variables
|
# Docker environment variables
|
||||||
|
|
||||||
: ${HOST_MAC:=''}
|
: "${HOST_MAC:=""}"
|
||||||
: ${HOST_DEBUG:=''}
|
: "${HOST_DEBUG:=""}"
|
||||||
: ${HOST_SERIAL:=''}
|
: "${HOST_SERIAL:=""}"
|
||||||
: ${HOST_MODEL:=''}
|
: "${HOST_MODEL:=""}"
|
||||||
: ${GUEST_SERIAL:=''}
|
: "${GUEST_SERIAL:=""}"
|
||||||
|
|
||||||
HOST_ARGS=()
|
HOST_ARGS=()
|
||||||
HOST_ARGS+=("-cpu=$CPU_CORES")
|
HOST_ARGS+=("-cpu=$CPU_CORES")
|
||||||
@@ -46,9 +46,13 @@ done
|
|||||||
|
|
||||||
# Configure serial ports
|
# Configure serial ports
|
||||||
|
|
||||||
SERIAL_OPTS="\
|
if [[ "$CONSOLE" != [Yy]* ]]; then
|
||||||
-chardev pty,id=charserial0 \
|
SERIAL_OPTS="-serial pty"
|
||||||
-device isa-serial,chardev=charserial0,id=serial0 \
|
else
|
||||||
|
SERIAL_OPTS="-serial mon:stdio"
|
||||||
|
fi
|
||||||
|
|
||||||
|
SERIAL_OPTS="$SERIAL_OPTS \
|
||||||
-device virtio-serial-pci,id=virtio-serial0,bus=pcie.0,addr=0x3 \
|
-device virtio-serial-pci,id=virtio-serial0,bus=pcie.0,addr=0x3 \
|
||||||
-chardev socket,id=charchannel0,host=127.0.0.1,port=12345,reconnect=10 \
|
-chardev socket,id=charchannel0,host=127.0.0.1,port=12345,reconnect=10 \
|
||||||
-device virtserialport,bus=virtio-serial0.0,nr=1,chardev=charchannel0,id=channel0,name=vchannel"
|
-device virtserialport,bus=virtio-serial0.0,nr=1,chardev=charchannel0,id=channel0,name=vchannel"
|
||||||
|
|||||||
@@ -1,66 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
set -eu
|
|
||||||
|
|
||||||
TMP_FILE=$(mktemp -q /tmp/server.XXXXXX)
|
|
||||||
|
|
||||||
stop() {
|
|
||||||
trap - SIGINT EXIT
|
|
||||||
{ pkill -f socat || true; } 2>/dev/null
|
|
||||||
[ -f "$TMP_FILE" ] && rm -f "$TMP_FILE"
|
|
||||||
}
|
|
||||||
|
|
||||||
trap 'stop' EXIT SIGINT SIGTERM SIGHUP
|
|
||||||
|
|
||||||
html()
|
|
||||||
{
|
|
||||||
local h="<!DOCTYPE html><HTML><HEAD><TITLE>VirtualDSM</TITLE>"
|
|
||||||
h="$h<STYLE>body { color: white; background-color: #125bdb; font-family: Verdana,"
|
|
||||||
h="$h Arial,sans-serif; } a, a:hover, a:active, a:visited { color: white; }</STYLE></HEAD>"
|
|
||||||
h="$h<BODY><BR><BR><H1><CENTER>$1</CENTER></H1></BODY></HTML>"
|
|
||||||
|
|
||||||
echo "$h"
|
|
||||||
}
|
|
||||||
|
|
||||||
if [[ "$2" != "/"* ]]; then
|
|
||||||
|
|
||||||
BODY="$2"
|
|
||||||
|
|
||||||
if [[ "$BODY" == "install" ]]; then
|
|
||||||
BODY="Please wait while Virtual DSM is being installed..."
|
|
||||||
BODY="$BODY<script>setTimeout(() => { document.location.reload(); }, 9999);</script>"
|
|
||||||
fi
|
|
||||||
|
|
||||||
HTML=$(html "$BODY")
|
|
||||||
printf '%b' "HTTP/1.1 200 OK\nContent-Length: ${#HTML}\nConnection: close\n\n$HTML" > "$TMP_FILE"
|
|
||||||
|
|
||||||
socat TCP4-LISTEN:80,reuseaddr,fork,crlf SYSTEM:"cat $TMP_FILE" 2> /dev/null &
|
|
||||||
socat TCP4-LISTEN:"${1:-5000}",reuseaddr,fork,crlf SYSTEM:"cat $TMP_FILE" 2> /dev/null & wait $!
|
|
||||||
|
|
||||||
exit
|
|
||||||
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ "$2" != "/run/ip.sh" ]]; then
|
|
||||||
|
|
||||||
cp "$2" "$TMP_FILE"
|
|
||||||
|
|
||||||
else
|
|
||||||
|
|
||||||
BODY="The location of DSM is <a href='http://\$LOCATION'>http://\$LOCATION</a><script>"
|
|
||||||
BODY="$BODY setTimeout(function(){ window.location.assign('http://\$LOCATION'); }, 3000);</script>"
|
|
||||||
WAIT="Please wait while discovering IP...<script>setTimeout(() => { document.location.reload(); }, 4999);</script>"
|
|
||||||
|
|
||||||
HTML=$(html "xxx")
|
|
||||||
|
|
||||||
{ echo "#!/bin/bash"
|
|
||||||
echo "[ -f \"/run/dsm.url\" ] && LOCATION=\$(cat \"/run/dsm.url\")"
|
|
||||||
echo "HTML=\"$HTML\"; [ -z \"\$LOCATION\" ] && BODY=\"$WAIT\" || BODY=\"$BODY\"; HTML=\${HTML/xxx/\$BODY}"
|
|
||||||
echo "printf '%b' \"HTTP/1.1 200 OK\\nContent-Length: \${#HTML}\\nConnection: close\\n\\n\$HTML\""
|
|
||||||
} > "$TMP_FILE"
|
|
||||||
|
|
||||||
fi
|
|
||||||
|
|
||||||
chmod +x "$TMP_FILE"
|
|
||||||
|
|
||||||
socat TCP4-LISTEN:80,reuseaddr,fork,crlf SYSTEM:"$TMP_FILE" 2> /dev/null &
|
|
||||||
socat TCP4-LISTEN:"${1:-5000}",reuseaddr,fork,crlf SYSTEM:"$TMP_FILE" 2> /dev/null & wait $!
|
|
||||||
26
web/index.html
Normal file
26
web/index.html
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
[1]
|
||||||
|
<meta http-equiv="Cache-Control" content="no-cache" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<link rel="stylesheet" type="text/css" href="style.css" />
|
||||||
|
[2]
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div id="page-container">
|
||||||
|
<div id="content-wrap">
|
||||||
|
<h1>[3]</h1>
|
||||||
|
</div>
|
||||||
|
<div id="empty-space">
|
||||||
|
</div>
|
||||||
|
<div id="footer">
|
||||||
|
[4]<br />
|
||||||
|
[5]
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
33
web/nginx.conf
Normal file
33
web/nginx.conf
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
listen [::]:80;
|
||||||
|
listen 5000 default_server;
|
||||||
|
listen [::]:5000 default_server;
|
||||||
|
|
||||||
|
autoindex on;
|
||||||
|
tcp_nodelay on;
|
||||||
|
server_tokens off;
|
||||||
|
absolute_redirect off;
|
||||||
|
|
||||||
|
error_log /dev/null;
|
||||||
|
access_log /dev/null;
|
||||||
|
|
||||||
|
include /etc/nginx/mime.types;
|
||||||
|
|
||||||
|
gzip on;
|
||||||
|
gzip_vary on;
|
||||||
|
gzip_proxied any;
|
||||||
|
gzip_comp_level 5;
|
||||||
|
gzip_min_length 500;
|
||||||
|
gzip_disable "msie6";
|
||||||
|
gzip_types text/css text/javascript text/xml text/plain text/x-component application/javascript application/json application/xml application/rss+xml font/truetype font/opentype application/vnd.ms-fontobject image/svg+xml;
|
||||||
|
|
||||||
|
add_header Cache-Control "no-cache";
|
||||||
|
|
||||||
|
location / {
|
||||||
|
|
||||||
|
root /run/shm;
|
||||||
|
index index.html;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
59
web/style.css
Normal file
59
web/style.css
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
body {
|
||||||
|
color: white;
|
||||||
|
background-color: #125bdb;
|
||||||
|
font-family: Verdana, Arial, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
#content-wrap {
|
||||||
|
text-align: center;
|
||||||
|
padding: 20px;
|
||||||
|
margin-top: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#footer {
|
||||||
|
width: 98%;
|
||||||
|
position: fixed;
|
||||||
|
bottom: 0px;
|
||||||
|
height: 40px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#empty-space {
|
||||||
|
height: 40px;
|
||||||
|
/* Same height as footer */
|
||||||
|
}
|
||||||
|
|
||||||
|
a,
|
||||||
|
a:hover,
|
||||||
|
a:active,
|
||||||
|
a:visited {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading:after {
|
||||||
|
content: " .";
|
||||||
|
animation: dots 1s steps(5, end) infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes dots {
|
||||||
|
|
||||||
|
0%,
|
||||||
|
20% {
|
||||||
|
color: rgba(0, 0, 0, 0);
|
||||||
|
text-shadow: 0.25em 0 0 rgba(0, 0, 0, 0), 0.5em 0 0 rgba(0, 0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
40% {
|
||||||
|
color: white;
|
||||||
|
text-shadow: 0.25em 0 0 rgba(0, 0, 0, 0), 0.5em 0 0 rgba(0, 0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
60% {
|
||||||
|
text-shadow: 0.25em 0 0 white, 0.5em 0 0 rgba(0, 0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
80%,
|
||||||
|
100% {
|
||||||
|
text-shadow: 0.25em 0 0 white, 0.5em 0 0 white;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user