mirror of
https://github.com/vdsm/virtual-dsm.git
synced 2026-08-29 20:26:57 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7b741d3e4b | ||
|
|
f1d29212ae | ||
|
|
fdee9f89a3 | ||
|
|
210a360797 | ||
|
|
991bb2627a | ||
|
|
764a186836 | ||
|
|
726786a98a | ||
|
|
2caf97d407 | ||
|
|
0e67286599 | ||
|
|
2b9fc80275 | ||
|
|
0d88774bd3 | ||
|
|
fa23052ed4 | ||
|
|
cc3267f258 | ||
|
|
fd002564a6 | ||
|
|
2703a97cfa | ||
|
|
29e2d034bf | ||
|
|
cbe3644335 |
@@ -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. |
|
||||||
@@ -22,7 +22,7 @@ Virtual DSM in a Docker container.
|
|||||||
- Near-native performance with KVM acceleration
|
- Near-native performance with KVM acceleration
|
||||||
- Customizable CPU, memory, and storage allocation
|
- Customizable CPU, memory, and storage allocation
|
||||||
- Supports multiple disks and physical disk passthrough
|
- Supports multiple disks and physical disk passthrough
|
||||||
- Supports bridge, user-mode, macvlan, and macvtap networking
|
- Supports NAT, user-mode, macvlan, and macvtap networking
|
||||||
|
|
||||||
## Usage 🐳
|
## 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.
|
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?
|
### What are the differences compared to the standard DSM?
|
||||||
|
|
||||||
There are only two minor differences: the Virtual Machine Manager package is not available, and Surveillance Station will not include any free licenses.
|
There are only two minor differences: the Virtual Machine Manager package is not available, and Surveillance Station will not include any free licenses.
|
||||||
|
|||||||
+58
-19
@@ -179,6 +179,22 @@ normalizeSize() {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
baseDir() {
|
||||||
|
|
||||||
|
local path="${1%/}"
|
||||||
|
|
||||||
|
[[ -z "$path" || "$path" == "/" ]] && {
|
||||||
|
echo "/"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
path="${path#/}"
|
||||||
|
path="${path%%/*}"
|
||||||
|
|
||||||
|
echo "/$path"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
createDisk() {
|
createDisk() {
|
||||||
|
|
||||||
local DISK_FILE="$1"
|
local DISK_FILE="$1"
|
||||||
@@ -186,7 +202,7 @@ createDisk() {
|
|||||||
local DISK_DESC="$3"
|
local DISK_DESC="$3"
|
||||||
local DISK_FMT="$4"
|
local DISK_FMT="$4"
|
||||||
local FS="$5"
|
local FS="$5"
|
||||||
local DATA_SIZE DIR SPACE GB FA
|
local DATA_SIZE DIR BASE_DIR SPACE GB FA
|
||||||
|
|
||||||
rm -f "$DISK_FILE"
|
rm -f "$DISK_FILE"
|
||||||
|
|
||||||
@@ -196,11 +212,16 @@ createDisk() {
|
|||||||
|
|
||||||
# Check free diskspace
|
# Check free diskspace
|
||||||
DIR=$(dirname "$DISK_FILE")
|
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
|
if (( DATA_SIZE > SPACE )); then
|
||||||
GB=$(formatBytes "$SPACE")
|
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
|
error "Please specify a smaller ${DISK_DESC^^}_SIZE or disable preallocation by setting ALLOCATE=N." && exit 76
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -255,7 +276,7 @@ resizeDisk() {
|
|||||||
local DISK_DESC="$3"
|
local DISK_DESC="$3"
|
||||||
local DISK_FMT="$4"
|
local DISK_FMT="$4"
|
||||||
local FS="$5"
|
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
|
CUR_SIZE=$(getSize "$DISK_FILE") || exit 71
|
||||||
DATA_SIZE=$(numfmt --from=iec "$DISK_SPACE")
|
DATA_SIZE=$(numfmt --from=iec "$DISK_SPACE")
|
||||||
@@ -266,11 +287,16 @@ resizeDisk() {
|
|||||||
|
|
||||||
# Check free diskspace
|
# Check free diskspace
|
||||||
DIR=$(dirname "$DISK_FILE")
|
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
|
if (( REQ > SPACE )); then
|
||||||
GB=$(formatBytes "$SPACE")
|
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
|
error "Please specify a smaller ${DISK_DESC^^}_SIZE or disable preallocation by setting ALLOCATE=N." && exit 74
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -317,8 +343,9 @@ convertDisk() {
|
|||||||
local TMP_FILE="$DISK_BASE.tmp"
|
local TMP_FILE="$DISK_BASE.tmp"
|
||||||
rm -f "$TMP_FILE"
|
rm -f "$TMP_FILE"
|
||||||
|
|
||||||
local DIR FA
|
local DIR BASE_DIR FA
|
||||||
DIR=$(dirname "$TMP_FILE")
|
DIR=$(dirname "$TMP_FILE")
|
||||||
|
BASE_DIR=$(baseDir "$DIR")
|
||||||
|
|
||||||
if ! disabled "$ALLOCATE"; then
|
if ! disabled "$ALLOCATE"; then
|
||||||
|
|
||||||
@@ -326,11 +353,15 @@ convertDisk() {
|
|||||||
|
|
||||||
# Check free diskspace
|
# Check free diskspace
|
||||||
CUR_SIZE=$(getSize "$SOURCE_FILE") || exit 79
|
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
|
if (( CUR_SIZE > SPACE )); then
|
||||||
GB=$(formatBytes "$SPACE")
|
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
|
error "Please free up some disk space or disable preallocation by setting ALLOCATE=N." && exit 76
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -353,13 +384,18 @@ convertDisk() {
|
|||||||
# shellcheck disable=SC2086
|
# shellcheck disable=SC2086
|
||||||
if ! qemu-img convert -f "$SOURCE_FMT" $CONV_FLAGS -o "$DISK_PARAM" -O "$DST_FMT" -- "$SOURCE_FILE" "$TMP_FILE"; then
|
if ! qemu-img convert -f "$SOURCE_FMT" $CONV_FLAGS -o "$DISK_PARAM" -O "$DST_FMT" -- "$SOURCE_FILE" "$TMP_FILE"; then
|
||||||
rm -f "$TMP_FILE"
|
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
|
fi
|
||||||
|
|
||||||
if [[ "$DST_FMT" == "raw" ]]; then
|
if [[ "$DST_FMT" == "raw" ]]; then
|
||||||
if ! disabled "$ALLOCATE"; then
|
if ! disabled "$ALLOCATE"; then
|
||||||
|
|
||||||
# Work around qemu-img bug
|
# 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 "$CUR_SIZE" "$TMP_FILE" &>/dev/null; then
|
||||||
if ! fallocate -l -x "$CUR_SIZE" "$TMP_FILE"; then
|
if ! fallocate -l -x "$CUR_SIZE" "$TMP_FILE"; then
|
||||||
error "Failed to allocate $CUR_SIZE bytes for $DISK_DESC image $TMP_FILE"
|
error "Failed to allocate $CUR_SIZE bytes for $DISK_DESC image $TMP_FILE"
|
||||||
@@ -399,21 +435,22 @@ checkFS () {
|
|||||||
local FS="$1"
|
local FS="$1"
|
||||||
local DISK_FILE="$2"
|
local DISK_FILE="$2"
|
||||||
local DISK_DESC="$3"
|
local DISK_DESC="$3"
|
||||||
local DIR FA
|
local DIR BASE_DIR FA
|
||||||
|
|
||||||
DIR=$(dirname "$DISK_FILE")
|
DIR=$(dirname "$DISK_FILE")
|
||||||
|
BASE_DIR=$(baseDir "$DIR")
|
||||||
[ ! -d "$DIR" ] && return 0
|
[ ! -d "$DIR" ] && return 0
|
||||||
|
|
||||||
if [[ "${FS,,}" == "overlay"* && "${ENGINE,,}" == "docker" ]]; then
|
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
|
fi
|
||||||
|
|
||||||
if [[ "${FS,,}" == "fuse"* ]]; then
|
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
|
fi
|
||||||
|
|
||||||
if ! supportsDirect "$FS"; then
|
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
|
fi
|
||||||
|
|
||||||
if isCow "$FS"; then
|
if isCow "$FS"; then
|
||||||
@@ -486,7 +523,7 @@ finishDisks () {
|
|||||||
|
|
||||||
case "${DISK_TYPE,,}" in
|
case "${DISK_TYPE,,}" in
|
||||||
"blk" | "scsi" | "virtio-blk" | "virtio-scsi" )
|
"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
|
esac
|
||||||
|
|
||||||
if ! enabled "$DISK_DISABLE"; then
|
if ! enabled "$DISK_DISABLE"; then
|
||||||
@@ -577,8 +614,9 @@ addDisk () {
|
|||||||
|
|
||||||
if (( LEFT > 0 )); then
|
if (( LEFT > 0 )); then
|
||||||
|
|
||||||
local GB
|
local GB BASE_DIR
|
||||||
GB=$(formatBytes "$FREE")
|
GB=$(formatBytes "$FREE")
|
||||||
|
BASE_DIR=$(baseDir "$DIR")
|
||||||
LEFT=$(formatBytes "$LEFT")
|
LEFT=$(formatBytes "$LEFT")
|
||||||
CUR_SIZE=$(formatBytes "$CUR_SIZE")
|
CUR_SIZE=$(formatBytes "$CUR_SIZE")
|
||||||
msg="The virtual size of the ${DISK_DESC,,} is $CUR_SIZE"
|
msg="The virtual size of the ${DISK_DESC,,} is $CUR_SIZE"
|
||||||
@@ -588,8 +626,8 @@ addDisk () {
|
|||||||
msg+=" (of which $USED is used)"
|
msg+=" (of which $USED is used)"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
info "$msg, but there is only $GB of free space remaining in $DIR now."
|
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 $DIR for future expansions."
|
info "Please consider making at least $LEFT more space available in $BASE_DIR for future expansions."
|
||||||
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -598,6 +636,7 @@ addDisk () {
|
|||||||
if [ -f "$DISK_FILE" ]; then
|
if [ -f "$DISK_FILE" ]; then
|
||||||
if ! setOwner "$DISK_FILE"; then
|
if ! setOwner "$DISK_FILE"; then
|
||||||
error "Failed to set the owner for \"$DISK_FILE\" !"
|
error "Failed to set the owner for \"$DISK_FILE\" !"
|
||||||
|
exit 77
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -26,7 +26,7 @@ trap - ERR
|
|||||||
|
|
||||||
cmd=(qemu-system-x86_64)
|
cmd=(qemu-system-x86_64)
|
||||||
version=$("${cmd[@]}" --version | awk 'NR==1 { print $4 }')
|
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
|
if ! enabled "$SHUTDOWN"; then
|
||||||
exec "${cmd[@]}" ${ARGS:+ $ARGS}
|
exec "${cmd[@]}" ${ARGS:+ $ARGS}
|
||||||
|
|||||||
+175
-64
@@ -52,7 +52,7 @@ ADD_ERR="Please add the following setting to your container:"
|
|||||||
isNAT() {
|
isNAT() {
|
||||||
|
|
||||||
case "${NETWORK,,}" in
|
case "${NETWORK,,}" in
|
||||||
"tap" | "tun" | "tuntap" | "y" | "" )
|
"nat" | "tap" | "tun" | "tuntap" | "y" | "" )
|
||||||
return 0 ;;
|
return 0 ;;
|
||||||
*)
|
*)
|
||||||
return 1 ;;
|
return 1 ;;
|
||||||
@@ -347,7 +347,7 @@ configureDNS() {
|
|||||||
|
|
||||||
# Set DHCP range and host
|
# Set DHCP range and host
|
||||||
arguments+=" --dhcp-range=$ip,$ip"
|
arguments+=" --dhcp-range=$ip,$ip"
|
||||||
arguments+=" --dhcp-host=$mac,,$ip,$host,infinite"
|
arguments+=" --dhcp-host=$mac,,$ip,$host,1h"
|
||||||
|
|
||||||
# Set DNS server and gateway
|
# Set DNS server and gateway
|
||||||
arguments+=" --dhcp-option=option:netmask,$mask"
|
arguments+=" --dhcp-option=option:netmask,$mask"
|
||||||
@@ -413,14 +413,37 @@ configureDNS() {
|
|||||||
|
|
||||||
getHostPorts() {
|
getHostPorts() {
|
||||||
|
|
||||||
local list="${HOST_PORTS// /},"
|
|
||||||
local ports=""
|
local ports=""
|
||||||
local port=""
|
local port=""
|
||||||
|
local num=""
|
||||||
|
local proto=""
|
||||||
|
local mode="${1:-tcp}"
|
||||||
|
local list="${HOST_PORTS// /},"
|
||||||
|
|
||||||
for port in ${list//,/ }; do
|
for port in ${list//,/ }; do
|
||||||
port="${port%/tcp}"
|
|
||||||
port="${port%/udp}"
|
proto="tcp"
|
||||||
[ -n "$port" ] && ports+="$port,"
|
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
|
done
|
||||||
|
|
||||||
# Remove duplicates
|
# Remove duplicates
|
||||||
@@ -432,39 +455,51 @@ getHostPorts() {
|
|||||||
|
|
||||||
getUserPorts() {
|
getUserPorts() {
|
||||||
|
|
||||||
local ssh="22"
|
local ssh="22/tcp"
|
||||||
local dsm="5000,5001"
|
local dsm="5000/tcp,5001/tcp"
|
||||||
|
|
||||||
local list="$ssh,$dsm,"
|
local list="$ssh,$dsm,"
|
||||||
list+="${USER_PORTS// /},"
|
list+="${USER_PORTS// /},"
|
||||||
|
|
||||||
local exclude
|
local exclude=""
|
||||||
exclude=$(getHostPorts)
|
exclude=$(getHostPorts "all")
|
||||||
|
|
||||||
local ports=""
|
local ports=""
|
||||||
local userport=""
|
local userport=""
|
||||||
local hostport=""
|
local hostport=""
|
||||||
|
local proto=""
|
||||||
|
local num=""
|
||||||
|
|
||||||
for userport in ${list//,/ }; do
|
for userport in ${list//,/ }; do
|
||||||
|
|
||||||
local num="${userport///tcp}"
|
proto="tcp"
|
||||||
num="${num///udp}"
|
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
|
for hostport in ${exclude//,/ }; do
|
||||||
|
|
||||||
local port="${hostport///tcp}"
|
if [[ "$num/$proto" == "$hostport" ]]; then
|
||||||
port="${port///udp}"
|
|
||||||
|
|
||||||
if [[ "$num" == "$port" ]]; then
|
|
||||||
num=""
|
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
|
fi
|
||||||
|
|
||||||
|
break
|
||||||
fi
|
fi
|
||||||
|
|
||||||
done
|
done
|
||||||
|
|
||||||
[ -n "$num" ] && ports+="$userport,"
|
[ -n "$num" ] && ports+="$num/$proto,"
|
||||||
|
|
||||||
done
|
done
|
||||||
|
|
||||||
@@ -490,10 +525,6 @@ getSlirp() {
|
|||||||
if [[ "$port" == *"/udp" ]]; then
|
if [[ "$port" == *"/udp" ]]; then
|
||||||
proto="udp"
|
proto="udp"
|
||||||
num="${port%/udp}"
|
num="${port%/udp}"
|
||||||
elif [[ "$port" != *"/tcp" ]]; then
|
|
||||||
args+="hostfwd=$proto::$num-$ip:$num,"
|
|
||||||
proto="udp"
|
|
||||||
num="${port%/udp}"
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
args+="hostfwd=$proto::$num-$ip:$num,"
|
args+="hostfwd=$proto::$num-$ip:$num,"
|
||||||
@@ -531,7 +562,6 @@ getPasst() {
|
|||||||
else
|
else
|
||||||
|
|
||||||
tcp+="$port,"
|
tcp+="$port,"
|
||||||
udp+="$port,"
|
|
||||||
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -655,7 +685,10 @@ configureSlirp() {
|
|||||||
[ -n "$forward" ] && NET_OPTS+=",$forward"
|
[ -n "$forward" ] && NET_OPTS+=",$forward"
|
||||||
|
|
||||||
if enabled "${DNSMASQ_DISABLE:-}"; then
|
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
|
else
|
||||||
if [ ! -f /etc/resolv.dnsmasq ] && ! cp /etc/resolv.conf /etc/resolv.dnsmasq; then
|
if [ ! -f /etc/resolv.dnsmasq ] && ! cp /etc/resolv.conf /etc/resolv.dnsmasq; then
|
||||||
error "Failed to backup /etc/resolv.conf."
|
error "Failed to backup /etc/resolv.conf."
|
||||||
@@ -846,7 +879,11 @@ configureTables() {
|
|||||||
local tables_err="failed to configure IP tables!"
|
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"
|
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 [ -n "$exclude" ]; then
|
||||||
if [[ "$exclude" != *","* ]]; then
|
if [[ "$exclude" != *","* ]]; then
|
||||||
@@ -927,11 +964,10 @@ configureTables() {
|
|||||||
warn "$tables_err" && return 1
|
warn "$tables_err" && return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Allow return traffic
|
# Allow forwarding from dev -> guest
|
||||||
if ! iptables -A FORWARD \
|
if ! iptables -A FORWARD \
|
||||||
-i "$DEV" \
|
-i "$DEV" \
|
||||||
-o "$BRIDGE" \
|
-o "$BRIDGE" \
|
||||||
-m conntrack --ctstate RELATED,ESTABLISHED \
|
|
||||||
-m comment --comment "$rule_tag" \
|
-m comment --comment "$rule_tag" \
|
||||||
-j ACCEPT; then
|
-j ACCEPT; then
|
||||||
warn "$tables_err" && return 1
|
warn "$tables_err" && return 1
|
||||||
@@ -1013,47 +1049,97 @@ configureNAT() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# ######################################
|
# ######################################
|
||||||
# Cleanup
|
# IP Tables
|
||||||
# ######################################
|
# ######################################
|
||||||
|
|
||||||
clearTables() {
|
setTables() {
|
||||||
|
|
||||||
local table="" line rules
|
local mode="$1"
|
||||||
local rule_tag="remove"
|
local path=""
|
||||||
local re="--comment[[:space:]]+\"?$rule_tag\"?([[:space:]]|\$)"
|
|
||||||
|
|
||||||
# Choose between iptables or nftables
|
path=$(command -v "iptables-$mode" 2>/dev/null || true)
|
||||||
if command -v iptables-nft >/dev/null 2>&1 && iptables-nft -V >/dev/null 2>&1; then
|
[ -z "$path" ] && return 1
|
||||||
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
|
|
||||||
|
|
||||||
# Store the current iptables ruleset
|
update-alternatives --set iptables "$path" > /dev/null 2>&1
|
||||||
! rules=$(iptables-save 2> /dev/null) && return 0
|
}
|
||||||
[ -z "$rules" ] && return 0
|
|
||||||
|
|
||||||
# Delete every rule tagged with our unique identifier, leaving all other rules intact.
|
testTables() {
|
||||||
while IFS= read -r line; do
|
|
||||||
case "$line" in
|
# Test actual ruleset access instead of only checking the binary version.
|
||||||
\*nat) table="nat" ;;
|
iptables -w -t nat -S > /dev/null 2>&1 || return 1
|
||||||
\*filter) table="filter" ;;
|
iptables-save -t nat > /dev/null 2>&1 || return 1
|
||||||
\*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"
|
|
||||||
|
|
||||||
return 0
|
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() {
|
closeBridge() {
|
||||||
|
|
||||||
local pids=( "$PASST_PID" "$DNSMASQ_PID" )
|
local pids=( "$PASST_PID" "$DNSMASQ_PID" )
|
||||||
@@ -1065,7 +1151,7 @@ closeBridge() {
|
|||||||
ip link set "$BRIDGE" down &> /dev/null || :
|
ip link set "$BRIDGE" down &> /dev/null || :
|
||||||
ip link delete "$BRIDGE" &> /dev/null || :
|
ip link delete "$BRIDGE" &> /dev/null || :
|
||||||
|
|
||||||
clearTables
|
clearTables || :
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1163,6 +1249,15 @@ validateHost() {
|
|||||||
return 0
|
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() {
|
validateAddresses() {
|
||||||
|
|
||||||
# DHCP/macvtap mode can work without a detectable container IPv4 address,
|
# DHCP/macvtap mode can work without a detectable container IPv4 address,
|
||||||
@@ -1262,8 +1357,16 @@ configureMAC() {
|
|||||||
if [ -z "$MAC" ]; then
|
if [ -z "$MAC" ]; then
|
||||||
# Generate a Synology-style MAC address based on a stable container identifier when possible.
|
# 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/')
|
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
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -1407,6 +1510,7 @@ prepareNetwork() {
|
|||||||
|
|
||||||
validateMask
|
validateMask
|
||||||
validateHost
|
validateHost
|
||||||
|
validateHostPorts
|
||||||
|
|
||||||
detectAddresses
|
detectAddresses
|
||||||
validateAddresses
|
validateAddresses
|
||||||
@@ -1437,8 +1541,15 @@ enabled "$DEBUG" && echo "$msg"
|
|||||||
|
|
||||||
prepareNetwork
|
prepareNetwork
|
||||||
|
|
||||||
echo "$UPLINK" > "$QEMU_DIR"/qemu.ip
|
if ! echo "$UPLINK" > "$QEMU_DIR"/qemu.ip; then
|
||||||
echo "$NIC" > "$QEMU_DIR"/qemu.nic
|
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
|
cleanUp
|
||||||
|
|
||||||
|
|||||||
+28
-45
@@ -53,6 +53,32 @@ checkSse42() {
|
|||||||
return 0
|
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() {
|
configureKvmCpuModel() {
|
||||||
|
|
||||||
CPU_FEATURES="kvm=on,l3-cache=on,+hypervisor"
|
CPU_FEATURES="kvm=on,l3-cache=on,+hypervisor"
|
||||||
@@ -130,52 +156,9 @@ configureTcg() {
|
|||||||
return 0
|
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() {
|
composeCpuFlags() {
|
||||||
|
|
||||||
if [ -z "$CPU_FLAGS" ]; then
|
CPU_FLAGS="${CPU_MODEL}${CPU_FEATURES:+,$CPU_FEATURES}${CPU_FLAGS:+,$CPU_FLAGS}"
|
||||||
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
|
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
@@ -211,7 +194,7 @@ else
|
|||||||
configureTcg
|
configureTcg
|
||||||
fi
|
fi
|
||||||
|
|
||||||
extractHostCpuArgument
|
removeCpuArgument
|
||||||
composeCpuFlags
|
composeCpuFlags
|
||||||
configureHostCpuName
|
configureHostCpuName
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -27,12 +27,12 @@ do
|
|||||||
if [ ! -s "$path" ] && [ ! -d "$path" ]; then
|
if [ ! -s "$path" ] && [ ! -d "$path" ]; then
|
||||||
bytes="0"
|
bytes="0"
|
||||||
else
|
else
|
||||||
bytes=$(du -sb "$path" | cut -f1)
|
bytes=$(du -sb "$path" 2>/dev/null | cut -f1) || bytes="0"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if (( bytes > 4096 )); then
|
if (( bytes > 4096 )); then
|
||||||
if [ -z "$total" ] || [[ "$total" == "0" ]] || [ "$bytes" -gt "$total" ]; 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
|
else
|
||||||
size="$(echo "$bytes" "$total" | awk '{printf "%.1f", $1 * 100 / $2}')"
|
size="$(echo "$bytes" "$total" | awk '{printf "%.1f", $1 * 100 / $2}')"
|
||||||
size="$size%"
|
size="$size%"
|
||||||
|
|||||||
+1
-1
@@ -9,7 +9,7 @@ refresh() {
|
|||||||
[ ! -f "$path" ] && return 0
|
[ ! -f "$path" ] && return 0
|
||||||
[ ! -s "$path" ] && return 0
|
[ ! -s "$path" ] && return 0
|
||||||
|
|
||||||
msg=$(< "$path")
|
msg=$(< "$path") || return 0
|
||||||
msg="${msg%$'\n'}"
|
msg="${msg%$'\n'}"
|
||||||
|
|
||||||
[ -z "$msg" ] && return 0
|
[ -z "$msg" ] && return 0
|
||||||
|
|||||||
+6
-6
@@ -188,8 +188,8 @@ setOwner() {
|
|||||||
[ ! -f "$file" ] && return 1
|
[ ! -f "$file" ] && return 1
|
||||||
|
|
||||||
dir=$(dirname -- "$file")
|
dir=$(dirname -- "$file")
|
||||||
uid=$(stat -c '%u' "$dir")
|
uid=$(stat -c '%u' "$dir") || return 1
|
||||||
gid=$(stat -c '%g' "$dir")
|
gid=$(stat -c '%g' "$dir") || return 1
|
||||||
|
|
||||||
! chown "$uid:$gid" "$file" && return 1
|
! chown "$uid:$gid" "$file" && return 1
|
||||||
|
|
||||||
@@ -204,8 +204,8 @@ makeDir() {
|
|||||||
! mkdir -p "$path" && return 1
|
! mkdir -p "$path" && return 1
|
||||||
|
|
||||||
dir=$(dirname -- "$path")
|
dir=$(dirname -- "$path")
|
||||||
uid=$(stat -c '%u' "$dir")
|
uid=$(stat -c '%u' "$dir") || return 1
|
||||||
gid=$(stat -c '%g' "$dir")
|
gid=$(stat -c '%g' "$dir") || return 1
|
||||||
|
|
||||||
! chown "$uid:$gid" "$path" && return 1
|
! chown "$uid:$gid" "$path" && return 1
|
||||||
|
|
||||||
@@ -247,8 +247,8 @@ html() {
|
|||||||
HTML="${HTML/\[4\]/$footer}"
|
HTML="${HTML/\[4\]/$footer}"
|
||||||
HTML="${HTML/\[5\]/$FOOTER2}"
|
HTML="${HTML/\[5\]/$FOOTER2}"
|
||||||
|
|
||||||
echo "$HTML" > "$PAGE"
|
echo "$HTML" > "$PAGE" || return 1
|
||||||
echo "$body" > "$INFO"
|
echo "$body" > "$INFO" || return 1
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user