Compare commits

...
17 Commits
Author SHA1 Message Date
KroeseandGitHub 7b741d3e4b feat: Warn about UDP host ports (#1250) 2026-07-12 22:14:11 +02:00
KroeseandGitHub f1d29212ae feat: Improve iptables rule cleanup (#1249) 2026-07-12 21:58:49 +02:00
KroeseandGitHub fdee9f89a3 feat: Improve iptables backend selection (#1248) 2026-07-12 21:36:52 +02:00
KroeseandGitHub 210a360797 fix: Restore compatible NAT forwarding rules (#1247) 2026-07-12 13:18:52 +03:00
KroeseandGitHub 991bb2627a fix: Prefer legacy iptables backend for NAT (#1246) 2026-07-12 12:44:00 +03:00
KroeseandGitHub 764a186836 feat: Allow all forwarded NAT traffic (#1245) 2026-07-11 11:58:35 +03:00
KroeseandGitHub 726786a98a feat: Default host and user ports to TCP only (#1244) 2026-07-09 11:06:01 +02:00
KroeseandGitHub 2caf97d407 docs: Network modes (#1243) 2026-07-09 00:39:52 +02:00
KroeseandGitHub 0e67286599 fix: Improve file handling (#1242) 2026-07-08 23:55:02 +02:00
KroeseandGitHub 2b9fc80275 feat: Validate MAC file writes (#1241) 2026-07-08 23:28:56 +02:00
KroeseandGitHub 0d88774bd3 feat: Display base directory in warnings (#1240) 2026-07-08 23:16:20 +02:00
KroeseandGitHub fa23052ed4 fix: Set default DHCP lease time to 1 hour (#1239) 2026-07-08 22:46:47 +02:00
KroeseandGitHub cc3267f258 docs: Correct hostname (#1238) 2026-07-08 18:57:55 +02:00
KroeseandGitHub fd002564a6 feat: Validate custom QEMU CPU arguments (#1237) 2026-07-08 18:50:31 +02:00
KroeseandGitHub 2703a97cfa docs: Refer to environment documentation (#1236) 2026-07-08 18:44:04 +02:00
KroeseandGitHub 29e2d034bf docs: Document all environment variables (#1235) 2026-07-08 17:11:10 +02:00
KroeseandGitHub cbe3644335 fix: Add extra line after boot (#1234) 2026-07-08 16:50:21 +02:00
9 changed files with 368 additions and 140 deletions
+91
View File
@@ -0,0 +1,91 @@
# Environment Variables
This page lists all the environment variables that can be used to configure the container.
## 💽 Virtual DSM
| Variable | Default | Description |
|---|---|---|
| `URL` | | URL or local path of the DSM `.pat` installation file. When unset, the default Virtual DSM image is downloaded automatically. |
| `HOST_MAC` | | MAC address reported to DSM. |
| `HOST_MODEL` | | Synology host device model reported to DSM. |
| `HOST_SERIAL` | | Synology host serial number reported to DSM. |
| `GUEST_SERIAL` | | Synology guest serial number reported to DSM. |
## 🧠 CPU and Memory
| Variable | Default | Description |
|---|---|---|
| `CPU_CORES` | `2` | Number of CPU cores assigned to the VM. Can also be set to `max` or `half`. |
| `CPU_MODEL` | `host` | QEMU CPU model to use. |
| `CPU_FLAGS` | | Additional QEMU CPU flags. |
| `HOST_CPU` | | CPU name reported to DSM. Automatically selected when unset. |
| `KVM` | `Y` | Enables KVM hardware acceleration. Set to `N` to disable. |
| `RAM_SIZE` | `2G` | Amount of RAM assigned to the VM, for example `2G`, `4G`, `max`, or `half`. |
| `RAM_CHECK` | `Y` | Checks whether enough host memory is available before starting the VM. |
## 💾 Storage
| Variable | Default | Description |
|---|---|---|
| `DISK_SIZE` | `256G` | Size of the main data disk. |
| `DISK_FMT` | `raw` | Disk image format, usually `raw` or `qcow2`. |
| `DISK_TYPE` | `scsi` | Disk controller/device type, such as `sata`, `scsi`, `nvme`, or `blk`. |
| `DISK_CACHE` | `none` | QEMU disk cache mode, for example `none` or `writeback`. |
| `DISK_IO` | `native` | QEMU disk I/O mode, for example `native`, `threads`, or `io_uring`. |
| `DISK_DISCARD` | `unmap` | Enables TRIM/unmap support for the data disk. |
| `DISK_ROTATION` | `1` | Rotation rate reported to the guest. Use `1` for SSD-like storage. |
| `DISK_FLAGS` | | Additional options used when creating qcow2 disks. |
| `ALLOCATE` | `N` | Preallocates disk space when creating the data disk. |
| `STORAGE` | `/storage` | Storage directory used for disks, firmware variables, and generated files. |
## 🌐 Networking
| Variable | Default | Description |
|---|---|---|
| `NETWORK` | `Y` | Network mode. Common values are `Y` for NAT, `passt`, `slirp`, or `N` to disable networking. |
| `DHCP` | `N` | Enables DHCP/macvtap mode so the VM receives an address from the external LAN. |
| `IP` | | Guest IP address override. |
| `MAC` | | Guest network adapter MAC address. |
| `HOST` | `VirtualDSM` | Hostname assigned to the VM. |
| `DEV` | `eth0` | Host/container network interface to use. |
| `MTU` | | Network MTU to use for the guest interface. |
| `MASK` | `255.255.255.0` | IPv4 netmask. |
| `TAP` | `dsm` | TAP/macvtap interface name. |
| `BRIDGE` | `docker` | Bridge name used for NAT networking. |
| `ADAPTER` | `virtio-net-pci` | QEMU network adapter model. |
| `HOST_PORTS` | | Ports reserved for services running on the host/container side. |
| `USER_PORTS` | | Additional ports to forward to the VM when using user-mode networking. |
| `DNSMASQ_OPTS` | | Additional dnsmasq options. |
| `DNSMASQ_DEBUG` | `N` | Enables dnsmasq log tailing. |
| `DNSMASQ_DISABLE` | `N` | Disables the internal dnsmasq resolver. |
| `PASST_OPTS` | | Additional passt options. |
| `PASST_DEBUG` | `N` | Enables passt debug output. |
## 🖥️ Display
| Variable | Default | Description |
|---|---|---|
| `DISPLAY` | `none` | QEMU display backend. Common values are `vnc`, `disabled`, or `none`. |
| `VGA` | `none` | QEMU video adapter model. |
| `GPU` | `N` | Enables Intel iGPU acceleration. |
| `RENDERNODE` | `/dev/dri/renderD128` | Render node used for GPU acceleration. |
## 🔌 Shutdown
| Variable | Default | Description |
|---|---|---|
| `SHUTDOWN` | `Y` | Enables graceful shutdown. |
| `TIMEOUT` | `115` | Timeout used while waiting for DSM to shut down. |
| `API_TIMEOUT` | `90` | Timeout used for the shutdown API call. |
## 🐞 Debugging
| Variable | Default | Description |
|---|---|---|
| `DEBUG` | `N` | Enables verbose debug output. |
| `TRACE` | `N` | Enables shell command tracing. |
| `COM_PORT` | `2210` | Internal communication port used by the DSM host helper. |
| `CHR_PORT` | `12345` | Internal character device port used by the DSM host helper. |
| `HOST_DEBUG` | `N` | Enables debug output for the host helper. |
| `ARGUMENTS` | | Additional raw QEMU arguments appended to the generated command line. |
+5 -1
View File
@@ -22,7 +22,7 @@ Virtual DSM in a Docker container.
- Near-native performance with KVM acceleration
- Customizable CPU, memory, and storage allocation
- Supports multiple disks and physical disk passthrough
- Supports bridge, user-mode, macvlan, and macvtap networking
- Supports NAT, user-mode, macvlan, and macvtap networking
## Usage 🐳
@@ -261,6 +261,10 @@ kubectl apply -f https://raw.githubusercontent.com/vdsm/virtual-dsm/refs/heads/m
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.
### Are these all available options?
No. For a complete overview of all supported settings, see the [environment variables](docs/environment.md) page.
### 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.
+58 -19
View File
@@ -179,6 +179,22 @@ normalizeSize() {
return 0
}
baseDir() {
local path="${1%/}"
[[ -z "$path" || "$path" == "/" ]] && {
echo "/"
return 0
}
path="${path#/}"
path="${path%%/*}"
echo "/$path"
return 0
}
createDisk() {
local DISK_FILE="$1"
@@ -186,7 +202,7 @@ createDisk() {
local DISK_DESC="$3"
local DISK_FMT="$4"
local FS="$5"
local DATA_SIZE DIR SPACE GB FA
local DATA_SIZE DIR BASE_DIR SPACE GB FA
rm -f "$DISK_FILE"
@@ -196,11 +212,16 @@ createDisk() {
# Check free diskspace
DIR=$(dirname "$DISK_FILE")
SPACE=$(df --output=avail -B 1 "$DIR" | tail -n 1)
BASE_DIR=$(baseDir "$DIR")
if ! SPACE=$(df --output=avail -B 1 "$DIR" | tail -n 1); then
error "Failed to check free space in $BASE_DIR."
exit 76
fi
if (( DATA_SIZE > SPACE )); then
GB=$(formatBytes "$SPACE")
error "Not enough free space to create a $DISK_DESC of ${DISK_SPACE/G/ GB} in $DIR, it has only $GB available..."
error "Not enough free space to create a $DISK_DESC of ${DISK_SPACE/G/ GB} in $BASE_DIR, it has only $GB available..."
error "Please specify a smaller ${DISK_DESC^^}_SIZE or disable preallocation by setting ALLOCATE=N." && exit 76
fi
@@ -255,7 +276,7 @@ resizeDisk() {
local DISK_DESC="$3"
local DISK_FMT="$4"
local FS="$5"
local CUR_SIZE DATA_SIZE DIR SPACE GB
local CUR_SIZE DATA_SIZE DIR BASE_DIR SPACE GB
CUR_SIZE=$(getSize "$DISK_FILE") || exit 71
DATA_SIZE=$(numfmt --from=iec "$DISK_SPACE")
@@ -266,11 +287,16 @@ resizeDisk() {
# Check free diskspace
DIR=$(dirname "$DISK_FILE")
SPACE=$(df --output=avail -B 1 "$DIR" | tail -n 1)
BASE_DIR=$(baseDir "$DIR")
if ! SPACE=$(df --output=avail -B 1 "$DIR" | tail -n 1); then
error "Failed to check free space in $BASE_DIR."
exit 76
fi
if (( REQ > SPACE )); then
GB=$(formatBytes "$SPACE")
error "Not enough free space to resize $DISK_DESC to ${DISK_SPACE/G/ GB} in $DIR, it has only $GB available.."
error "Not enough free space to resize $DISK_DESC to ${DISK_SPACE/G/ GB} in $BASE_DIR, it has only $GB available.."
error "Please specify a smaller ${DISK_DESC^^}_SIZE or disable preallocation by setting ALLOCATE=N." && exit 74
fi
@@ -317,8 +343,9 @@ convertDisk() {
local TMP_FILE="$DISK_BASE.tmp"
rm -f "$TMP_FILE"
local DIR FA
local DIR BASE_DIR FA
DIR=$(dirname "$TMP_FILE")
BASE_DIR=$(baseDir "$DIR")
if ! disabled "$ALLOCATE"; then
@@ -326,11 +353,15 @@ convertDisk() {
# Check free diskspace
CUR_SIZE=$(getSize "$SOURCE_FILE") || exit 79
SPACE=$(df --output=avail -B 1 "$DIR" | tail -n 1)
if ! SPACE=$(df --output=avail -B 1 "$DIR" | tail -n 1); then
error "Failed to check free space in $BASE_DIR."
exit 76
fi
if (( CUR_SIZE > SPACE )); then
GB=$(formatBytes "$SPACE")
error "Not enough free space to convert $DISK_DESC to $DST_FMT in $DIR, it has only $GB available..."
error "Not enough free space to convert $DISK_DESC to $DST_FMT in $BASE_DIR, it has only $GB available..."
error "Please free up some disk space or disable preallocation by setting ALLOCATE=N." && exit 76
fi
@@ -353,13 +384,18 @@ convertDisk() {
# shellcheck disable=SC2086
if ! qemu-img convert -f "$SOURCE_FMT" $CONV_FLAGS -o "$DISK_PARAM" -O "$DST_FMT" -- "$SOURCE_FILE" "$TMP_FILE"; then
rm -f "$TMP_FILE"
error "Failed to convert $DISK_STYLE $DISK_DESC image to $DST_FMT format in $DIR, is there enough space available?" && exit 79
error "Failed to convert $DISK_STYLE $DISK_DESC image to $DST_FMT format in $BASE_DIR, is there enough space available?" && exit 79
fi
if [[ "$DST_FMT" == "raw" ]]; then
if ! disabled "$ALLOCATE"; then
# Work around qemu-img bug
CUR_SIZE=$(stat -c%s "$TMP_FILE")
if ! CUR_SIZE=$(stat -c%s "$TMP_FILE"); then
error "Failed to determine converted image size: $TMP_FILE"
exit 79
fi
if ! fallocate -l "$CUR_SIZE" "$TMP_FILE" &>/dev/null; then
if ! fallocate -l -x "$CUR_SIZE" "$TMP_FILE"; then
error "Failed to allocate $CUR_SIZE bytes for $DISK_DESC image $TMP_FILE"
@@ -399,21 +435,22 @@ checkFS () {
local FS="$1"
local DISK_FILE="$2"
local DISK_DESC="$3"
local DIR FA
local DIR BASE_DIR FA
DIR=$(dirname "$DISK_FILE")
BASE_DIR=$(baseDir "$DIR")
[ ! -d "$DIR" ] && return 0
if [[ "${FS,,}" == "overlay"* && "${ENGINE,,}" == "docker" ]]; then
warn "the filesystem of $DIR is OverlayFS, this usually means it was binded to an invalid path!"
warn "the filesystem of $BASE_DIR is OverlayFS, this usually means it was binded to an invalid path!"
fi
if [[ "${FS,,}" == "fuse"* ]]; then
warn "the filesystem of $DIR is FUSE, this extra layer will negatively affect performance!"
warn "the filesystem of $BASE_DIR is FUSE, this extra layer will negatively affect performance!"
fi
if ! supportsDirect "$FS"; then
warn "the filesystem of $DIR is $FS, which does not support O_DIRECT mode, adjusting settings..."
warn "the filesystem of $BASE_DIR is $FS, which does not support O_DIRECT mode, adjusting settings..."
fi
if isCow "$FS"; then
@@ -486,7 +523,7 @@ finishDisks () {
case "${DISK_TYPE,,}" in
"blk" | "scsi" | "virtio-blk" | "virtio-scsi" )
DISK_OPTS+=" -object iothread,id=io2" ;;
[[ "$DISK_OPTS" != *" -object iothread,id=io2"* ]] && DISK_OPTS+=" -object iothread,id=io2" ;;
esac
if ! enabled "$DISK_DISABLE"; then
@@ -577,8 +614,9 @@ addDisk () {
if (( LEFT > 0 )); then
local GB
local GB BASE_DIR
GB=$(formatBytes "$FREE")
BASE_DIR=$(baseDir "$DIR")
LEFT=$(formatBytes "$LEFT")
CUR_SIZE=$(formatBytes "$CUR_SIZE")
msg="The virtual size of the ${DISK_DESC,,} is $CUR_SIZE"
@@ -588,8 +626,8 @@ addDisk () {
msg+=" (of which $USED is used)"
fi
info "$msg, but there is only $GB of free space remaining in $DIR now."
info "Please consider making at least $LEFT more space available in $DIR for future expansions."
info "$msg, but there is only $GB of free space remaining in $BASE_DIR now."
info "Please consider making at least $LEFT more space available in $BASE_DIR for future expansions."
fi
@@ -598,6 +636,7 @@ addDisk () {
if [ -f "$DISK_FILE" ]; then
if ! setOwner "$DISK_FILE"; then
error "Failed to set the owner for \"$DISK_FILE\" !"
exit 77
fi
fi
+1 -1
View File
@@ -26,7 +26,7 @@ trap - ERR
cmd=(qemu-system-x86_64)
version=$("${cmd[@]}" --version | awk 'NR==1 { print $4 }')
info "Booting $APP using QEMU v$version..."
info "Booting $APP using QEMU v$version..." && echo
if ! enabled "$SHUTDOWN"; then
exec "${cmd[@]}" ${ARGS:+ $ARGS}
+176 -65
View File
@@ -52,7 +52,7 @@ ADD_ERR="Please add the following setting to your container:"
isNAT() {
case "${NETWORK,,}" in
"tap" | "tun" | "tuntap" | "y" | "" )
"nat" | "tap" | "tun" | "tuntap" | "y" | "" )
return 0 ;;
*)
return 1 ;;
@@ -347,7 +347,7 @@ configureDNS() {
# Set DHCP range and host
arguments+=" --dhcp-range=$ip,$ip"
arguments+=" --dhcp-host=$mac,,$ip,$host,infinite"
arguments+=" --dhcp-host=$mac,,$ip,$host,1h"
# Set DNS server and gateway
arguments+=" --dhcp-option=option:netmask,$mask"
@@ -413,14 +413,37 @@ configureDNS() {
getHostPorts() {
local list="${HOST_PORTS// /},"
local ports=""
local port=""
local num=""
local proto=""
local mode="${1:-tcp}"
local list="${HOST_PORTS// /},"
for port in ${list//,/ }; do
port="${port%/tcp}"
port="${port%/udp}"
[ -n "$port" ] && ports+="$port,"
proto="tcp"
num="$port"
if [[ "$port" == *"/udp" ]]; then
proto="udp"
num="${port%/udp}"
elif [[ "$port" == *"/tcp" ]]; then
proto="tcp"
num="${port%/tcp}"
fi
[ -z "$num" ] && continue
case "$mode" in
"all" )
ports+="$num/$proto," ;;
"tcp" )
[[ "$proto" == "tcp" ]] && ports+="$num," ;;
"udp" )
[[ "$proto" == "udp" ]] && ports+="$num," ;;
esac
done
# Remove duplicates
@@ -432,39 +455,51 @@ getHostPorts() {
getUserPorts() {
local ssh="22"
local dsm="5000,5001"
local ssh="22/tcp"
local dsm="5000/tcp,5001/tcp"
local list="$ssh,$dsm,"
list+="${USER_PORTS// /},"
local exclude
exclude=$(getHostPorts)
local exclude=""
exclude=$(getHostPorts "all")
local ports=""
local userport=""
local hostport=""
local proto=""
local num=""
for userport in ${list//,/ }; do
local num="${userport///tcp}"
num="${num///udp}"
proto="tcp"
num="$userport"
if [[ "$userport" == *"/udp" ]]; then
proto="udp"
num="${userport%/udp}"
elif [[ "$userport" == *"/tcp" ]]; then
proto="tcp"
num="${userport%/tcp}"
fi
[ -z "$num" ] && continue
for hostport in ${exclude//,/ }; do
local port="${hostport///tcp}"
port="${port///udp}"
if [[ "$num" == "$port" ]]; then
if [[ "$num/$proto" == "$hostport" ]]; then
num=""
if [[ "$port" != "${WEB_PORT:-}" ]]; then
warn "Could not assign port $port to \"USER_PORTS\" because it is already in \"HOST_PORTS\"!"
if [[ "$hostport" != "${WEB_PORT:-}/tcp" ]]; then
warn "Could not assign port $hostport to \"USER_PORTS\" because it is already in \"HOST_PORTS\"!"
fi
break
fi
done
[ -n "$num" ] && ports+="$userport,"
[ -n "$num" ] && ports+="$num/$proto,"
done
@@ -490,10 +525,6 @@ getSlirp() {
if [[ "$port" == *"/udp" ]]; then
proto="udp"
num="${port%/udp}"
elif [[ "$port" != *"/tcp" ]]; then
args+="hostfwd=$proto::$num-$ip:$num,"
proto="udp"
num="${port%/udp}"
fi
args+="hostfwd=$proto::$num-$ip:$num,"
@@ -531,7 +562,6 @@ getPasst() {
else
tcp+="$port,"
udp+="$port,"
fi
@@ -655,7 +685,10 @@ configureSlirp() {
[ -n "$forward" ] && NET_OPTS+=",$forward"
if enabled "${DNSMASQ_DISABLE:-}"; then
echo "$gateway" > /run/shm/qemu.gw || warn "Failed to write gateway file."
if ! echo "$gateway" > /run/shm/qemu.gw; then
error "Failed to write gateway file."
return 1
fi
else
if [ ! -f /etc/resolv.dnsmasq ] && ! cp /etc/resolv.conf /etc/resolv.dnsmasq; then
error "Failed to backup /etc/resolv.conf."
@@ -846,7 +879,11 @@ configureTables() {
local tables_err="failed to configure IP tables!"
local tables="the 'ip_tables' kernel module is not loaded. Try this command: sudo modprobe ip_tables iptable_nat"
clearTables
if ! clearTables; then
enabled "$ROOTLESS" && ! enabled "$DEBUG" && return 1
warn "failed to select a working IP tables backend!"
return 1
fi
if [ -n "$exclude" ]; then
if [[ "$exclude" != *","* ]]; then
@@ -927,11 +964,10 @@ configureTables() {
warn "$tables_err" && return 1
fi
# Allow return traffic
# Allow forwarding from dev -> guest
if ! iptables -A FORWARD \
-i "$DEV" \
-o "$BRIDGE" \
-m conntrack --ctstate RELATED,ESTABLISHED \
-m comment --comment "$rule_tag" \
-j ACCEPT; then
warn "$tables_err" && return 1
@@ -1013,47 +1049,97 @@ configureNAT() {
}
# ######################################
# Cleanup
# IP Tables
# ######################################
clearTables() {
setTables() {
local table="" line rules
local rule_tag="remove"
local re="--comment[[:space:]]+\"?$rule_tag\"?([[:space:]]|\$)"
local mode="$1"
local path=""
# Choose between iptables or nftables
if command -v iptables-nft >/dev/null 2>&1 && iptables-nft -V >/dev/null 2>&1; then
update-alternatives --set iptables /usr/sbin/iptables-nft > /dev/null
update-alternatives --set ip6tables /usr/sbin/ip6tables-nft > /dev/null
else
update-alternatives --set iptables /usr/sbin/iptables-legacy > /dev/null
update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy > /dev/null
fi
path=$(command -v "iptables-$mode" 2>/dev/null || true)
[ -z "$path" ] && return 1
# Store the current iptables ruleset
! rules=$(iptables-save 2> /dev/null) && return 0
[ -z "$rules" ] && return 0
update-alternatives --set iptables "$path" > /dev/null 2>&1
}
# Delete every rule tagged with our unique identifier, leaving all other rules intact.
while IFS= read -r line; do
case "$line" in
\*nat) table="nat" ;;
\*filter) table="filter" ;;
\*mangle) table="mangle" ;;
\*raw) table="raw" ;;
esac
if [[ "$line" == -A* ]]; then
if [[ "$line" =~ $re ]]; then
read -ra args <<< "${line/-A /-D }"
iptables -t "$table" "${args[@]}" &> /dev/null || :
fi
fi
done <<< "$rules"
testTables() {
# Test actual ruleset access instead of only checking the binary version.
iptables -w -t nat -S > /dev/null 2>&1 || return 1
iptables-save -t nat > /dev/null 2>&1 || return 1
return 0
}
selectTables() {
local mode=""
local modes=()
# Prefer nftables for Podman namespaces, but retain legacy first for Docker.
if [[ "${ENGINE,,}" == "podman" ]]; then
modes=( "nft" "legacy" )
else
modes=( "legacy" "nft" )
fi
for mode in "${modes[@]}"; do
command -v "iptables-$mode" > /dev/null 2>&1 || continue
setTables "$mode" && testTables && return 0
done
return 1
}
clearTables() {
local table=""
local line=""
local rules=""
local failed="N"
local rule_tag="remove"
local re="--comment[[:space:]]+\"?$rule_tag\"?([[:space:]]|\$)"
selectTables || return 1
# Store the current iptables ruleset.
! rules=$(iptables-save 2> /dev/null) && return 1
[ -z "$rules" ] && return 0
# Delete every rule tagged with our unique identifier,
# leaving all other rules intact.
while IFS= read -r line; do
case "$line" in
\*nat ) table="nat" ;;
\*filter ) table="filter" ;;
\*mangle ) table="mangle" ;;
\*raw ) table="raw" ;;
esac
if [[ "$line" == -A* ]] && [[ "$line" =~ $re ]]; then
line="${line/-A /-D }"
# Parse the quoting produced by iptables-save before deleting the rule.
if ! printf '%s\n' "$line" |
xargs -r iptables -t "$table" > /dev/null 2>&1; then
failed="Y"
fi
fi
done <<< "$rules"
enabled "$failed" && return 1
return 0
}
# ######################################
# Cleanup
# ######################################
closeBridge() {
local pids=( "$PASST_PID" "$DNSMASQ_PID" )
@@ -1065,7 +1151,7 @@ closeBridge() {
ip link set "$BRIDGE" down &> /dev/null || :
ip link delete "$BRIDGE" &> /dev/null || :
clearTables
clearTables || :
return 0
}
@@ -1163,6 +1249,15 @@ validateHost() {
return 0
}
validateHostPorts() {
if isNAT && [[ "${HOST_PORTS,,}" == *"/udp"* ]]; then
warn "UDP ports in \"HOST_PORTS\" are not yet implemented for NAT networking."
fi
return 0
}
validateAddresses() {
# DHCP/macvtap mode can work without a detectable container IPv4 address,
@@ -1262,8 +1357,16 @@ configureMAC() {
if [ -z "$MAC" ]; then
# Generate a Synology-style MAC address based on a stable container identifier when possible.
MAC=$(echo "$container" | md5sum | sed 's/^\(..\)\(..\)\(..\)\(..\)\(..\).*$/02:11:32:\3:\4:\5/')
echo "${MAC^^}" > "$file"
! setOwner "$file" && error "Failed to set the owner for \"$file\" !"
if ! echo "${MAC^^}" > "$file"; then
error "Failed to write MAC address to \"$file\" !"
exit 28
fi
if ! setOwner "$file"; then
error "Failed to set the owner for \"$file\" !"
exit 28
fi
fi
fi
@@ -1354,7 +1457,7 @@ showHostInfo() {
[[ "$nameservers" == "127.0.0.1"* ]] && nameservers=""
echo
if (( ${#nameservers} <= 40 )); then
[ -n "$nameservers" ] && line+=" | DNS: $nameservers"
echo "$line"
@@ -1407,6 +1510,7 @@ prepareNetwork() {
validateMask
validateHost
validateHostPorts
detectAddresses
validateAddresses
@@ -1437,8 +1541,15 @@ enabled "$DEBUG" && echo "$msg"
prepareNetwork
echo "$UPLINK" > "$QEMU_DIR"/qemu.ip
echo "$NIC" > "$QEMU_DIR"/qemu.nic
if ! echo "$UPLINK" > "$QEMU_DIR"/qemu.ip; then
error "Failed to write QEMU IP file!"
exit 24
fi
if ! echo "$NIC" > "$QEMU_DIR"/qemu.nic; then
error "Failed to write QEMU NIC file!"
exit 24
fi
cleanUp
+28 -45
View File
@@ -53,6 +53,32 @@ checkSse42() {
return 0
}
trimSpaces() {
local value="$1"
value="${value#"${value%%[![:space:]]*}"}"
value="${value%"${value##*[![:space:]]}"}"
echo "$value"
return 0
}
removeCpuArgument() {
local args=" ${ARGUMENTS:-} "
while [[ "$args" =~ [[:space:]]-cpu([[:space:]][^[:space:]]+|=[^[:space:]]+)? ]]; do
local cpu="${BASH_REMATCH[0]}"
args="${args/$cpu/ }"
warn "Ignoring '${cpu#" "}' from ARGUMENTS, use CPU_MODEL and CPU_FLAGS instead."
done
ARGUMENTS=$(trimSpaces "$args")
return 0
}
configureKvmCpuModel() {
CPU_FEATURES="kvm=on,l3-cache=on,+hypervisor"
@@ -130,52 +156,9 @@ configureTcg() {
return 0
}
extractHostCpuArgument() {
local args prefix suffix param
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
return 0
}
composeCpuFlags() {
if [ -z "$CPU_FLAGS" ]; then
if [ -z "$CPU_FEATURES" ]; then
CPU_FLAGS="$CPU_MODEL"
else
CPU_FLAGS="$CPU_MODEL,$CPU_FEATURES"
fi
else
if [ -z "$CPU_FEATURES" ]; then
CPU_FLAGS="$CPU_MODEL,$CPU_FLAGS"
else
CPU_FLAGS="$CPU_MODEL,$CPU_FEATURES,$CPU_FLAGS"
fi
fi
CPU_FLAGS="${CPU_MODEL}${CPU_FEATURES:+,$CPU_FEATURES}${CPU_FLAGS:+,$CPU_FLAGS}"
return 0
}
@@ -211,7 +194,7 @@ else
configureTcg
fi
extractHostCpuArgument
removeCpuArgument
composeCpuFlags
configureHostCpuName
+2 -2
View File
@@ -27,12 +27,12 @@ do
if [ ! -s "$path" ] && [ ! -d "$path" ]; then
bytes="0"
else
bytes=$(du -sb "$path" | cut -f1)
bytes=$(du -sb "$path" 2>/dev/null | cut -f1) || bytes="0"
fi
if (( bytes > 4096 )); then
if [ -z "$total" ] || [[ "$total" == "0" ]] || [ "$bytes" -gt "$total" ]; 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/') || size="${bytes} bytes"
else
size="$(echo "$bytes" "$total" | awk '{printf "%.1f", $1 * 100 / $2}')"
size="$size%"
+1 -1
View File
@@ -9,7 +9,7 @@ refresh() {
[ ! -f "$path" ] && return 0
[ ! -s "$path" ] && return 0
msg=$(< "$path")
msg=$(< "$path") || return 0
msg="${msg%$'\n'}"
[ -z "$msg" ] && return 0
+6 -6
View File
@@ -188,8 +188,8 @@ setOwner() {
[ ! -f "$file" ] && return 1
dir=$(dirname -- "$file")
uid=$(stat -c '%u' "$dir")
gid=$(stat -c '%g' "$dir")
uid=$(stat -c '%u' "$dir") || return 1
gid=$(stat -c '%g' "$dir") || return 1
! chown "$uid:$gid" "$file" && return 1
@@ -204,8 +204,8 @@ makeDir() {
! mkdir -p "$path" && return 1
dir=$(dirname -- "$path")
uid=$(stat -c '%u' "$dir")
gid=$(stat -c '%g' "$dir")
uid=$(stat -c '%u' "$dir") || return 1
gid=$(stat -c '%g' "$dir") || return 1
! chown "$uid:$gid" "$path" && return 1
@@ -247,8 +247,8 @@ html() {
HTML="${HTML/\[4\]/$footer}"
HTML="${HTML/\[5\]/$FOOTER2}"
echo "$HTML" > "$PAGE"
echo "$body" > "$INFO"
echo "$HTML" > "$PAGE" || return 1
echo "$body" > "$INFO" || return 1
return 0
}