Compare commits

...

31 Commits

Author SHA1 Message Date
Kroese
a89007ee03
build: Use Github token (#1100) 2025-10-29 14:05:53 +01:00
Kroese
8a89149d58
feat: Check for SSE4 instruction set (#1099) 2025-10-29 08:32:42 +01:00
Kroese
5e8bbc2868
fix: Remove unnecessary operation (#1097) 2025-10-24 04:30:21 +02:00
Kroese
4e48920309
fix: Do not assume Podman never has privileges (#1096) 2025-10-24 01:19:38 +02:00
Kroese
8b145924b9
fix: Reduce spare disk space threshold (#1093)
Some checks failed
Update / dockerHubDescription (push) Has been cancelled
2025-10-22 02:47:50 +02:00
Kroese
a0328e1e9c
fix: Inherit owner from parent folder (#1092) 2025-10-22 02:38:57 +02:00
Kroese
b7f5214a7b
build: Add code quality checks (#1091) 2025-10-22 00:59:35 +02:00
Kroese
b0e4c4ac5f
docs: Update docker run command (#1090) 2025-10-21 23:15:31 +02:00
Kroese
bbb67aac93
build: Add review workflow for shell formatting (#1089) 2025-10-21 22:39:50 +02:00
Kroese
433c83b393
fix: Kill QEMU after 5 seconds if it hangs (#1088) 2025-10-19 17:56:44 +02:00
Kroese
5577178eeb
fix: Only display non-zero percentage (#1087) 2025-10-19 17:32:25 +02:00
Kroese
221b0242fa
fix: Kill QEMU after 5 seconds when it hangs (#1086) 2025-10-19 16:57:51 +02:00
Kroese
c05623f8af
fix: Round filesize up to nearest cluster (#1085) 2025-10-19 14:38:36 +02:00
Kroese
eb9884cc96
feat: Improve Github Codespaces configuration (#1084) 2025-10-19 12:48:40 +02:00
Kroese
8e2490e6bc
feat: Improve Github Codespaces configuration (#1082) 2025-10-19 10:40:03 +02:00
Kroese
399243886e
feat: Show directory size (#1083) 2025-10-19 09:40:45 +02:00
Kroese
b0dbfcb805
feat: Improve Github Codespaces configuration (#1081) 2025-10-19 01:14:11 +02:00
Kroese
dec2dc9230
feat: Check free diskspace during startup (#1080) 2025-10-17 16:47:43 +02:00
Kroese
2c44669d91
feat: Improve Codespaces configuration (#1079) 2025-10-17 13:25:02 +02:00
Kroese
175d90aad7
fix: Move order in entry file (#1078) 2025-10-17 13:04:03 +02:00
Kroese
e1e5f8f91d
fix: Validate status messages (#1077) 2025-10-17 12:07:13 +02:00
Kroese
dff8abbe1e
build: Validate JSON and YML files (#1076) 2025-10-17 10:05:52 +02:00
Kroese
0f97091e61
fix: Set network flag (#1075) 2025-10-17 01:39:49 +02:00
Kroese
ea0d7ee6cd
feat: Implement extra disksize preset (#1074) 2025-10-17 00:17:30 +02:00
Kroese
75daa31d36
feat: Implement extra CPU_CORES preset (#1073) 2025-10-17 00:15:56 +02:00
Kroese
8c44319c45
feat: Move memory check to own module (#1072) 2025-10-16 23:49:16 +02:00
Kroese
dac574d933
feat: Automatically adjust RAM size when too high (#1071) 2025-10-16 12:36:49 +02:00
Kroese
fd4c5001e8
feat: Update Github Codespaces configuration (#1070) 2025-10-16 09:43:19 +02:00
Kroese
dfe0b23995
feat: Improve Github Codespaces configuration (#1069) 2025-10-15 23:58:01 +02:00
Kroese
6158372eaa
fix: Remove nat option (#1068)
Some checks failed
Update / dockerHubDescription (push) Has been cancelled
2025-10-15 14:39:28 +02:00
Kroese
b1a778d7b2
docs: Readme (#1067) 2025-10-15 12:43:07 +02:00
20 changed files with 478 additions and 181 deletions

View File

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

View File

@ -1,9 +1,9 @@
services:
dsm:
container_name: dsm
image: vdsm/virtual-dsm
image: ghcr.io/vdsm/virtual-dsm
environment:
RAM_SIZE: "max"
RAM_SIZE: "half"
DISK_SIZE: "max"
CPU_CORES: "max"
devices:

View File

@ -0,0 +1,17 @@
{
"name": "Virtual DSM",
"service": "vdsm",
"forwardPorts": [5000],
"portsAttributes": {
"5000": {
"label": "Web",
"onAutoForward": "notify"
}
},
"otherPortsAttributes": {
"onAutoForward": "ignore"
},
"dockerComposeFile": "codespaces.yml",
"workspaceFolder": "/workspaces/vdsm",
"initializeCommand": "docker system prune --all --force"
}

View File

@ -1,4 +1,5 @@
.dockerignore
.devcontainer
.git
.github
.gitignore

View File

@ -22,3 +22,8 @@ jobs:
dockerfile: Dockerfile
ignore: DL3008,DL3003,DL3006,DL3013
failure-threshold: warning
-
name: Validate JSON and YML files
uses: GrantBirki/json-yaml-validate@v4
with:
yaml_exclude_regex: ".*\\kubernetes\\.yml$"

66
.github/workflows/review.yml vendored Normal file
View File

@ -0,0 +1,66 @@
on:
pull_request:
name: "Review"
permissions:
contents: read
pull-requests: write
checks: write
jobs:
review:
name: review
runs-on: ubuntu-latest
steps:
-
name: Checkout
uses: actions/checkout@v5
-
name: Spelling
uses: reviewdog/action-misspell@v1
with:
locale: "US"
level: warning
pattern: |
*.md
*.sh
reporter: github-pr-review
github_token: ${{ secrets.GITHUB_TOKEN }}
-
name: Hadolint
uses: reviewdog/action-hadolint@v1
with:
level: warning
reporter: github-pr-review
hadolint_ignore: DL3008 DL3003 DL3006 DL3013
github_token: ${{ secrets.GITHUB_TOKEN }}
-
name: YamlLint
uses: reviewdog/action-yamllint@v1
with:
level: warning
reporter: github-pr-review
github_token: ${{ secrets.GITHUB_TOKEN }}
-
name: ActionLint
uses: reviewdog/action-actionlint@v1
with:
level: warning
reporter: github-pr-review
github_token: ${{ secrets.GITHUB_TOKEN }}
-
name: Shellformat
uses: reviewdog/action-shfmt@v1
with:
level: warning
shfmt_flags: "-i 2 -ci -bn"
github_token: ${{ secrets.GITHUB_TOKEN }}
-
name: Shellcheck
uses: reviewdog/action-shellcheck@v1
with:
level: warning
reporter: github-pr-review
shellcheck_flags: -x -e SC2001 -e SC2034 -e SC2064 -e SC2317 -e SC2153 -e SC2028
github_token: ${{ secrets.GITHUB_TOKEN }}

View File

@ -47,7 +47,7 @@ services:
##### Via Docker CLI:
```bash
docker run -it --rm --name dsm -e "DISK_SIZE=256G" -p 5000:5000 --device=/dev/kvm --device=/dev/net/tun --cap-add NET_ADMIN -v "${PWD:-.}/dsm:/storage" --stop-timeout 120 vdsm/virtual-dsm
docker run -it --rm --name dsm -e "DISK_SIZE=256G" -p 5000:5000 --device=/dev/kvm --device=/dev/net/tun --cap-add NET_ADMIN -v "${PWD:-.}/dsm:/storage" --stop-timeout 120 docker.io/vdsm/virtual-dsm
```
##### Via Kubernetes:
@ -124,7 +124,7 @@ kubectl apply -f https://raw.githubusercontent.com/vdsm/virtual-dsm/refs/heads/m
### How do I change the amount of CPU or RAM?
By default, the container will be allowed to use a maximum of 2 CPU cores and 2 GB of RAM.
By default, Virtual DSM will be allowed to use 2 CPU cores and 2 GB of RAM.
If you want to adjust this, you can specify the desired amount using the following environment variables:

View File

@ -12,32 +12,4 @@ DEV_OPTS+=" -device virtio-rng-pci,rng=objrng0,id=rng0,bus=pcie.0,addr=0x1c"
ARGS="$DEF_OPTS $CPU_OPTS $RAM_OPTS $MAC_OPTS $DISPLAY_OPTS $MON_OPTS $SERIAL_OPTS $NET_OPTS $DISK_OPTS $DEV_OPTS $ARGUMENTS"
ARGS=$(echo "$ARGS" | sed 's/\t/ /g' | tr -s ' ')
# Check available memory as the very last step
if [[ "$RAM_CHECK" != [Nn]* ]]; then
RAM_AVAIL=$(free -b | grep -m 1 Mem: | awk '{print $7}')
AVAIL_MEM=$(formatBytes "$RAM_AVAIL")
if (( (RAM_WANTED + RAM_SPARE) > RAM_AVAIL )); then
msg="Your configured RAM_SIZE of ${RAM_SIZE/G/ GB} is too high for the $AVAIL_MEM of memory available, please set a lower value."
[[ "${FS,,}" != "zfs" ]] && error "$msg" && exit 17
info "$msg"
else
if (( (RAM_WANTED + (RAM_SPARE * 3)) > RAM_AVAIL )); then
msg="your configured RAM_SIZE of ${RAM_SIZE/G/ GB} is very close to the $AVAIL_MEM of memory available, please consider a lower value."
if [[ "${FS,,}" != "zfs" ]]; then
warn "$msg"
else
info "$msg"
fi
fi
fi
fi
if [[ "$DEBUG" == [Yy1]* ]]; then
printf "QEMU arguments:\n\n%s\n\n" "${ARGS// -/$'\n-'}"
fi
return 0

View File

@ -17,8 +17,16 @@ SYSTEM="$STORAGE/$BASE.system.img"
[ ! -s "$BOOT" ] && error "Virtual DSM boot-image does not exist ($BOOT)" && exit 81
[ ! -s "$SYSTEM" ] && error "Virtual DSM system-image does not exist ($SYSTEM)" && exit 82
if ! setOwner "$BOOT"; then
error "Failed to set the owner for \"$BOOT\" !"
fi
if ! setOwner "$SYSTEM"; then
error "Failed to set the owner for \"$SYSTEM\" !"
fi
fmt2ext() {
local DISK_FMT=$1
local DISK_FMT="$1"
case "${DISK_FMT,,}" in
qcow2)
@ -34,7 +42,7 @@ fmt2ext() {
}
ext2fmt() {
local DISK_EXT=$1
local DISK_EXT="$1"
case "${DISK_EXT,,}" in
qcow2)
@ -50,7 +58,7 @@ ext2fmt() {
}
getSize() {
local DISK_FILE=$1
local DISK_FILE="$1"
local DISK_EXT DISK_FMT
DISK_EXT=$(echo "${DISK_FILE//*./}" | sed 's/^.*\.//')
@ -70,7 +78,7 @@ getSize() {
}
isCow() {
local FS=$1
local FS="$1"
if [[ "${FS,,}" == "btrfs" ]]; then
return 0
@ -80,7 +88,7 @@ isCow() {
}
supportsDirect() {
local FS=$1
local FS="$1"
if [[ "${FS,,}" == "ecryptfs" || "${FS,,}" == "tmpfs" ]]; then
return 1
@ -91,11 +99,11 @@ supportsDirect() {
createDisk() {
local DISK_FILE=$1
local DISK_SPACE=$2
local DISK_DESC=$3
local DISK_FMT=$4
local FS=$5
local DISK_FILE="$1"
local DISK_SPACE="$2"
local DISK_DESC="$3"
local DISK_FMT="$4"
local FS="$5"
local DATA_SIZE DIR SPACE GB FA
rm -f "$DISK_FILE"
@ -113,6 +121,7 @@ createDisk() {
error "Not enough free space to create a $DISK_DESC of ${DISK_SPACE/G/ GB} in $DIR, it has only $GB available..."
error "Please specify a smaller ${DISK_DESC^^}_SIZE or disable preallocation by setting ALLOCATE=N." && exit 76
fi
fi
html "Creating a $DISK_DESC image..."
@ -177,16 +186,16 @@ createDisk() {
resizeDisk() {
local DISK_FILE=$1
local DISK_SPACE=$2
local DISK_DESC=$3
local DISK_FMT=$4
local FS=$5
local DISK_FILE="$1"
local DISK_SPACE="$2"
local DISK_DESC="$3"
local DISK_FMT="$4"
local FS="$5"
local CUR_SIZE DATA_SIZE DIR SPACE GB
CUR_SIZE=$(getSize "$DISK_FILE")
DATA_SIZE=$(numfmt --from=iec "$DISK_SPACE")
local REQ=$((DATA_SIZE-CUR_SIZE))
local REQ=$(( DATA_SIZE - CUR_SIZE ))
(( REQ < 1 )) && error "Shrinking disks is not supported yet, please increase ${DISK_DESC^^}_SIZE." && exit 71
if [[ "$ALLOCATE" != [Nn]* ]]; then
@ -200,6 +209,7 @@ resizeDisk() {
error "Not enough free space to resize $DISK_DESC to ${DISK_SPACE/G/ GB} in $DIR, it has only $GB available.."
error "Please specify a smaller ${DISK_DESC^^}_SIZE or disable preallocation by setting ALLOCATE=N." && exit 74
fi
fi
GB=$(formatBytes "$CUR_SIZE")
@ -245,13 +255,13 @@ resizeDisk() {
convertDisk() {
local SOURCE_FILE=$1
local SOURCE_FMT=$2
local DST_FILE=$3
local DST_FMT=$4
local DISK_BASE=$5
local DISK_DESC=$6
local FS=$7
local SOURCE_FILE="$1"
local SOURCE_FMT="$2"
local DST_FILE="$3"
local DST_FMT="$4"
local DISK_BASE="$5"
local DISK_DESC="$6"
local FS="$7"
[ -f "$DST_FILE" ] && error "Conversion failed, destination file $DST_FILE already exists?" && exit 79
[ ! -f "$SOURCE_FILE" ] && error "Conversion failed, source file $SOURCE_FILE does not exists?" && exit 79
@ -273,6 +283,7 @@ convertDisk() {
error "Not enough free space to convert $DISK_DESC to $DST_FMT in $DIR, it has only $GB available..."
error "Please free up some disk space or disable preallocation by setting ALLOCATE=N." && exit 76
fi
fi
local msg="Converting $DISK_DESC to $DST_FMT"
@ -327,31 +338,31 @@ convertDisk() {
checkFS () {
local FS=$1
local DISK_FILE=$2
local DISK_DESC=$3
local FS="$1"
local DISK_FILE="$2"
local DISK_DESC="$3"
local DIR FA
DIR=$(dirname "$DISK_FILE")
[ ! -d "$DIR" ] && return 0
if [[ "${FS,,}" == "overlay"* ]]; then
info "Warning: the filesystem of $DIR is OverlayFS, this usually means it was binded to an invalid path!"
if [[ "${FS,,}" == "overlay"* && "$PODMAN" != [Yy1]* ]]; then
warn "the filesystem of $DIR is OverlayFS, this usually means it was binded to an invalid path!"
fi
if [[ "${FS,,}" == "fuse"* ]]; then
info "Warning: the filesystem of $DIR is FUSE, this extra layer will negatively affect performance!"
warn "the filesystem of $DIR is FUSE, this extra layer will negatively affect performance!"
fi
if ! supportsDirect "$FS"; then
info "Warning: the filesystem of $DIR is $FS, which does not support O_DIRECT mode, adjusting settings..."
warn "the filesystem of $DIR is $FS, which does not support O_DIRECT mode, adjusting settings..."
fi
if isCow "$FS"; then
if [ -f "$DISK_FILE" ]; then
FA=$(lsattr "$DISK_FILE")
if [[ "$FA" != *"C"* ]]; then
info "Warning: COW (copy on write) is not disabled for $DISK_DESC image file $DISK_FILE, this is recommended on ${FS^^} filesystems!"
warn "COW (copy on write) is not disabled for $DISK_DESC image file $DISK_FILE, this is recommended on ${FS^^} filesystems!"
fi
fi
fi
@ -361,15 +372,15 @@ checkFS () {
createDevice () {
local DISK_FILE=$1
local DISK_TYPE=$2
local DISK_INDEX=$3
local DISK_ADDRESS=$4
local DISK_FMT=$5
local DISK_IO=$6
local DISK_CACHE=$7
local DISK_SERIAL=$8
local DISK_SECTORS=$9
local DISK_FILE="$1"
local DISK_TYPE="$2"
local DISK_INDEX="$3"
local DISK_ADDRESS="$4"
local DISK_FMT="$5"
local DISK_IO="$6"
local DISK_CACHE="$7"
local DISK_SERIAL="$8"
local DISK_SECTORS="$9"
local DISK_ID="data$DISK_INDEX"
local index=""
@ -415,16 +426,16 @@ createDevice () {
addDisk () {
local DISK_BASE=$1
local DISK_TYPE=$2
local DISK_DESC=$3
local DISK_SPACE=$4
local DISK_INDEX=$5
local DISK_ADDRESS=$6
local DISK_FMT=$7
local DISK_IO=$8
local DISK_CACHE=$9
local DISK_EXT DIR SPACE GB DATA_SIZE FS PREV_FMT PREV_EXT CUR_SIZE
local DISK_BASE="$1"
local DISK_TYPE="$2"
local DISK_DESC="$3"
local DISK_SPACE="$4"
local DISK_INDEX="$5"
local DISK_ADDRESS="$6"
local DISK_FMT="$7"
local DISK_IO="$8"
local DISK_CACHE="$9"
local DISK_EXT DIR SPACE GB DATA_SIZE FS PREV_FMT PREV_EXT CUR_SIZE LEFT FREE USED
DISK_EXT=$(fmt2ext "$DISK_FMT")
local DISK_FILE="$DISK_BASE.$DISK_EXT"
@ -432,18 +443,25 @@ addDisk () {
DIR=$(dirname "$DISK_FILE")
[ ! -d "$DIR" ] && return 0
if [[ "${DISK_SPACE,,}" == "max" ]]; then
if [[ "${DISK_SPACE,,}" == "max" || "${DISK_SPACE,,}" == "half" ]]; then
local SPARE=536870912
SPACE=$(df --output=avail -B 1 "$DIR" | tail -n 1)
(( SPACE < SPARE )) && SPACE="$SPARE" || SPACE=$((SPACE-SPARE))
GB=$(( SPACE/1073741825 ))
local SPARE=1073741824
FREE=$(df --output=avail -B 1 "$DIR" | tail -n 1)
if [[ "${DISK_SPACE,,}" == "max" ]]; then
FREE=$(( FREE - SPARE ))
else
FREE=$(( FREE / 2 ))
fi
(( FREE < SPARE )) && FREE="$SPARE"
GB=$(( FREE / 1073741825 ))
DISK_SPACE="${GB}G"
fi
SPACE="${DISK_SPACE// /}"
[ -z "$SPACE" ] && SPACE="16G"
[ -z "$SPACE" ] && SPACE="256G"
[ -z "${SPACE//[0-9. ]}" ] && SPACE="${SPACE}G"
SPACE=$(echo "${SPACE^^}" | sed 's/MB/M/g;s/GB/G/g;s/TB/T/g')
@ -454,7 +472,7 @@ addDisk () {
DATA_SIZE=$(numfmt --from=iec "$SPACE")
if (( DATA_SIZE < 6442450944 )); then
error "Please increase ${DISK_DESC^^}_SIZE to at least 6 GB." && exit 73
error "Please increase the ${DISK_DESC^^}_SIZE variable to at least 6 GB." && exit 73
fi
FS=$(stat -f -c %T "$DIR")
@ -465,7 +483,7 @@ addDisk () {
DISK_CACHE="writeback"
fi
if ! [ -s "$DISK_FILE" ] ; then
if [ ! -s "$DISK_FILE" ] ; then
if [[ "${DISK_FMT,,}" != "raw" ]]; then
PREV_FMT="raw"
@ -478,6 +496,7 @@ addDisk () {
if [ -s "$DISK_BASE.$PREV_EXT" ] ; then
convertDisk "$DISK_BASE.$PREV_EXT" "$PREV_FMT" "$DISK_FILE" "$DISK_FMT" "$DISK_BASE" "$DISK_DESC" "$FS" || exit $?
fi
fi
if [ -s "$DISK_FILE" ]; then
@ -485,7 +504,18 @@ addDisk () {
CUR_SIZE=$(getSize "$DISK_FILE")
if (( DATA_SIZE > CUR_SIZE )); then
resizeDisk "$DISK_FILE" "$SPACE" "$DISK_DESC" "$DISK_FMT" "$FS" || exit $?
else
if (( DATA_SIZE < CUR_SIZE )); then
if [[ "${DISK_SPACE,,}" != "max" && "${DISK_SPACE,,}" != "half" ]]; then
info "You decreased the ${DISK_DESC^^}_SIZE variable to ${DISK_SPACE/G/ GB} but shrinking disks is not supported, will be ignored..."
fi
fi
fi
else
@ -494,6 +524,39 @@ addDisk () {
fi
if [ -f "$DISK_FILE" ] && [[ "$ALLOCATE" == [Nn]* ]]; then
CUR_SIZE=$(getSize "$DISK_FILE")
USED=$(du -sB 1 "$DISK_FILE" | cut -f1)
FREE=$(df --output=avail -B 1 "$DIR" | tail -n 1)
LEFT=$(( CUR_SIZE - USED - FREE ))
if (( LEFT > 0 )); then
GB=$(formatBytes "$FREE")
LEFT=$(formatBytes "$LEFT")
CUR_SIZE=$(formatBytes "$CUR_SIZE")
msg="the virtual size of the ${DISK_DESC,,} is $CUR_SIZE"
if [[ "$USED" == "0" ]]; then
msg+=","
else
USED=$(formatBytes "$USED")
msg+=" (of which $USED is used),"
fi
warn "$msg but there is only $GB of free space left in $DIR, make at least $LEFT more room available!"
fi
fi
if [ -f "$DISK_FILE" ]; then
if ! setOwner "$DISK_FILE"; then
error "Failed to set the owner for \"$DISK_FILE\" !"
fi
fi
DISK_OPTS+=$(createDevice "$DISK_FILE" "$DISK_TYPE" "$DISK_INDEX" "$DISK_ADDRESS" "$DISK_FMT" "$DISK_IO" "$DISK_CACHE" "" "")
return 0
@ -501,10 +564,10 @@ addDisk () {
addDevice () {
local DISK_DEV=$1
local DISK_TYPE=$2
local DISK_INDEX=$3
local DISK_ADDRESS=$4
local DISK_DEV="$1"
local DISK_TYPE="$2"
local DISK_INDEX="$3"
local DISK_ADDRESS="$4"
[ -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
@ -516,7 +579,7 @@ addDevice () {
physical=$(echo "$result" | grep -m 1 -o "/ .*" | cut -c 3-)
physical="${physical%% *}"
if [ -n "$physical" ]; then
if [ -n "$physical" ]; then
if [[ "$physical" != "512" ]]; then
sectors=",logical_block_size=$logical,physical_block_size=$physical"
fi

View File

@ -18,7 +18,9 @@ cd /run
. proc.sh # Initialize processor
. serial.sh # Initialize serialport
. power.sh # Configure shutdown
. memory.sh # Check available memory
. config.sh # Configure arguments
. finish.sh # Finish initialization
trap - ERR

8
src/finish.sh Normal file
View File

@ -0,0 +1,8 @@
#!/usr/bin/env bash
set -Eeuo pipefail
if [[ "$DEBUG" == [Yy1]* ]]; then
printf "QEMU arguments:\n\n%s\n\n" "${ARGS// -/$'\n-'}"
fi
return 0

View File

@ -31,7 +31,6 @@ if [ -n "$URL" ] && [ ! -s "$FILE" ] && [ ! -d "$DIR" ]; then
BASE=$(basename "$URL" .pat)
if [ ! -s "$STORAGE/$BASE.system.img" ]; then
BASE=$(basename "${URL%%\?*}" .pat)
BASE="${BASE//+/ }"
printf -v BASE '%b' "${BASE//%/\\x}"
BASE="${BASE//[!A-Za-z0-9._-]/_}"
fi
@ -66,7 +65,6 @@ fi
if [ ! -s "$FILE" ]; then
BASE=$(basename "${URL%%\?*}" .pat)
BASE="${BASE//+/ }"
printf -v BASE '%b' "${BASE//%/\\x}"
BASE="${BASE//[!A-Za-z0-9._-]/_}"
fi
@ -82,16 +80,16 @@ rm -f "$STORAGE/$BASE.system.img"
# Check filesystem
FS=$(stat -f -c %T "$STORAGE")
if [[ "${FS,,}" == "overlay"* ]]; then
info "Warning: the filesystem of $STORAGE is OverlayFS, this usually means it was binded to an invalid path!"
if [[ "${FS,,}" == "overlay"* && "$PODMAN" != [Yy1]* ]]; then
warn "the filesystem of $STORAGE is OverlayFS, this usually means it was binded to an invalid path!"
fi
if [[ "${FS,,}" == "fuse"* ]]; then
info "Warning: the filesystem of $STORAGE is FUSE, this extra layer will negatively affect performance!"
warn "the filesystem of $STORAGE is FUSE, this extra layer will negatively affect performance!"
fi
if [[ "${FS,,}" == "ecryptfs" || "${FS,,}" == "tmpfs" ]]; then
info "Warning: the filesystem of $STORAGE is $FS, which does not support O_DIRECT mode, adjusting settings..."
warn "the filesystem of $STORAGE is $FS, which does not support O_DIRECT mode, adjusting settings..."
fi
if [[ "${FS,,}" == "fat"* || "${FS,,}" == "vfat"* || "${FS,,}" == "msdos"* ]]; then
@ -100,6 +98,10 @@ fi
if [[ "${FS,,}" != "exfat"* && "${FS,,}" != "ntfs"* && "${FS,,}" != "unknown"* ]]; then
TMP="$STORAGE/tmp"
rm -rf "$TMP"
if ! makeDir "$TMP"; then
error "Failed to create directory \"$TMP\" !" && exit 93
fi
else
TMP="/tmp/dsm"
TMP_SPACE=2147483648
@ -108,10 +110,9 @@ else
if (( TMP_SPACE > SPACE )); then
error "Not enough free space inside the container, have $SPACE_MB available but need at least 2 GB." && exit 93
fi
rm -rf "$TMP" && mkdir -p "$TMP"
fi
rm -rf "$TMP" && mkdir -p "$TMP"
# Check free diskspace
ROOT_SPACE=536870912
SPACE=$(df --output=avail -B 1 / | tail -n 1)
@ -224,6 +225,8 @@ if ! touch "$SYSTEM"; then
error "Could not create file $SYSTEM for the system disk." && exit 98
fi
! setOwner "$SYSTEM" && error "Failed to set the owner for \"$SYSTEM\" !"
if [[ "${FS,,}" == "btrfs" ]]; then
{ chattr +C "$SYSTEM"; } || :
FA=$(lsattr "$SYSTEM")
@ -256,7 +259,11 @@ PART="$TMP/partition.fdisk"
sfdisk -q "$SYSTEM" < "$PART"
MOUNT="$TMP/system"
rm -rf "$MOUNT" && mkdir -p "$MOUNT"
rm -rf "$MOUNT"
if ! makeDir "$MOUNT"; then
error "Failed to create directory \"$MOUNT\" !" && exit 93
fi
MSG="Extracting system partition..."
info "Install: $MSG" && html "$MSG"
@ -291,6 +298,7 @@ fakeroot -- bash -c "set -Eeu;\
rm -rf "$MOUNT"
echo "$BASE" > "$STORAGE/dsm.ver"
! setOwner "$STORAGE/dsm.ver" && error "Failed to set the owner for \"$STORAGE/dsm.ver\" !"
if [[ "$URL" == "file://$STORAGE/$BASE.pat" ]]; then
rm -f "$PAT"
@ -298,7 +306,13 @@ else
mv -f "$PAT" "$STORAGE/$BASE.pat"
fi
if [ -f "$STORAGE/$BASE.pat" ]; then
! setOwner "$STORAGE/$BASE.pat" && error "Failed to set the owner for \"$STORAGE/$BASE.pat\" !"
fi
mv -f "$BOOT" "$STORAGE/$BASE.boot.img"
! setOwner "$STORAGE/$BASE.boot.img" && error "Failed to set the owner for \"$STORAGE/$BASE.boot.img\" !"
rm -rf "$TMP"
return 0

86
src/memory.sh Normal file
View File

@ -0,0 +1,86 @@
#!/usr/bin/env bash
set -Eeuo pipefail
RAM_AVAIL=$(free -b | grep -m 1 Mem: | awk '{print $7}')
if [[ "$RAM_CHECK" != [Nn]* && "${RAM_SIZE,,}" != "max" && "${RAM_SIZE,,}" != "half" ]]; then
AVAIL_MEM=$(formatBytes "$RAM_AVAIL")
if (( (RAM_WANTED + RAM_SPARE) > RAM_AVAIL )); then
msg="Your configured RAM_SIZE of ${RAM_SIZE/G/ GB} is too high for the $AVAIL_MEM of memory available,"
if [[ "${FS,,}" == "zfs" ]]; then
info "$msg but since ZFS is active this will be ignored."
else
RAM_SIZE="max"
warn "$msg it will automatically be adjusted to a lower amount."
fi
else
if (( (RAM_WANTED + (RAM_SPARE * 3)) > RAM_AVAIL )); then
msg="your configured RAM_SIZE of ${RAM_SIZE/G/ GB} is very close to the $AVAIL_MEM of memory available,"
if [[ "${FS,,}" == "zfs" ]]; then
info "$msg but since ZFS is active this will be ignored."
else
warn "$msg please consider a lower amount."
fi
fi
fi
fi
if [[ "${RAM_SIZE,,}" == "half" ]]; then
RAM_WANTED=$(( RAM_AVAIL / 2 ))
RAM_WANTED=$(( RAM_WANTED / 1073741825 ))
if (( "$RAM_WANTED" < 1 )); then
RAM_WANTED=$(( RAM_AVAIL / 2 ))
RAM_WANTED=$(( RAM_WANTED / 1048577 ))
RAM_SIZE="${RAM_WANTED}M"
else
RAM_SIZE="${RAM_WANTED}G"
fi
fi
if [[ "${RAM_SIZE,,}" == "max" ]]; then
RAM_WANTED=$(( RAM_AVAIL - (RAM_SPARE * 3) ))
RAM_WANTED=$(( RAM_WANTED / 1073741825 ))
if (( "$RAM_WANTED" < 1 )); then
RAM_WANTED=$(( RAM_AVAIL - (RAM_SPARE * 2) ))
RAM_WANTED=$(( RAM_WANTED / 1073741825 ))
if (( "$RAM_WANTED" < 1 )); then
RAM_WANTED=$(( RAM_AVAIL - RAM_SPARE ))
RAM_WANTED=$(( RAM_WANTED / 1073741825 ))
if (( "$RAM_WANTED" < 1 )); then
RAM_WANTED=$(( RAM_AVAIL - RAM_SPARE ))
RAM_WANTED=$(( RAM_WANTED / 1048577 ))
if (( "$RAM_WANTED" < 1 )); then
RAM_WANTED=$(( RAM_AVAIL ))
RAM_WANTED=$(( RAM_WANTED / 1048577 ))
fi
RAM_SIZE="${RAM_WANTED}M"
else
RAM_SIZE="${RAM_WANTED}G"
fi
else
RAM_SIZE="${RAM_WANTED}G"
fi
else
RAM_SIZE="${RAM_WANTED}G"
fi
fi
return 0

View File

@ -131,7 +131,7 @@ configureDNS() {
rm -f "$log"
case "${NETWORK,,}" in
"nat" | "tap" | "tun" | "tuntap" | "y" )
"tap" | "tun" | "tuntap" | "y" )
# Create lease file for faster resolve
echo "0 $mac $ip $host 01:$mac" > /var/lib/misc/dnsmasq.leases
@ -218,11 +218,14 @@ getUserPorts() {
for hostport in ${exclude//,/ }; do
local val="${hostport///tcp}"
local port="${hostport///tcp}"
port="${port///udp}"
if [[ "$num" == "${val///udp}" ]]; then
if [[ "$num" == "$port" ]]; then
num=""
warn "Could not assign port ${val///udp} to \"USER_PORTS\" because it is already in \"HOST_PORTS\"!"
if [[ "$port" != "$WEB_PORT" ]]; then
warn "Could not assign port $port to \"USER_PORTS\" because it is already in \"HOST_PORTS\"!"
fi
fi
done
@ -271,6 +274,7 @@ getSlirp() {
configureSlirp() {
NETWORK="slirp"
[[ "$DEBUG" == [Yy1]* ]] && echo "Configuring slirp networking..."
local ip="$IP"
@ -302,6 +306,7 @@ configureSlirp() {
configurePasst() {
NETWORK="passt"
[[ "$DEBUG" == [Yy1]* ]] && echo "Configuring user-mode networking..."
local log="/var/log/passt.log"
@ -341,6 +346,12 @@ configurePasst() {
PASST_OPTS+=" -H $VM_NET_HOST"
PASST_OPTS+=" -M $GATEWAY_MAC"
local uid gid
uid=$(id -u)
gid=$(id -g)
PASST_OPTS+=" --runas $uid:$gid"
PASST_OPTS+=" -P /var/run/passt.pid"
PASST_OPTS+=" -l $log"
PASST_OPTS+=" -q"
@ -392,7 +403,6 @@ configureNAT() {
# Create the necessary file structure for /dev/net/tun
if [ ! -c /dev/net/tun ]; then
[[ "$PODMAN" == [Yy1]* ]] && return 1
[ ! -d /dev/net ] && mkdir -m 755 /dev/net
if mknod /dev/net/tun c 10 200; then
chmod 666 /dev/net/tun
@ -400,6 +410,7 @@ configureNAT() {
fi
if [ ! -c /dev/net/tun ]; then
[[ "$PODMAN" == [Yy1]* ]] && return 1
warn "$tuntap" && return 1
fi
@ -407,6 +418,7 @@ configureNAT() {
if [[ $(< /proc/sys/net/ipv4/ip_forward) -eq 0 ]]; then
{ sysctl -w net.ipv4.ip_forward=1 > /dev/null 2>&1; rc=$?; } || :
if (( rc != 0 )) || [[ $(< /proc/sys/net/ipv4/ip_forward) -eq 0 ]]; then
[[ "$PODMAN" == [Yy1]* ]] && return 1
warn "IP forwarding is disabled. $ADD_ERR --sysctl net.ipv4.ip_forward=1"
return 1
fi
@ -433,6 +445,7 @@ configureNAT() {
{ ip link add dev "$VM_NET_BRIDGE" type bridge ; rc=$?; } || :
if (( rc != 0 )); then
[[ "$PODMAN" == [Yy1]* ]] && return 1
warn "failed to create bridge. $ADD_ERR --cap-add NET_ADMIN" && return 1
fi
@ -447,6 +460,7 @@ configureNAT() {
# QEMU Works with taps, set tap to the bridge created
if ! ip tuntap add dev "$VM_NET_TAP" mode tap; then
[[ "$PODMAN" == [Yy1]* ]] && return 1
warn "$tuntap" && return 1
fi
@ -695,7 +709,7 @@ getInfo() {
[ -z "$MTU" ] && MTU="0"
if [[ "${ADAPTER,,}" != "virtio-net-pci" ]]; then
if [[ "$MTU" != "0" && "$MTU" != "1500" ]]; then
if [[ "$MTU" != "0" ]] && [ "$MTU" -lt "1500" ]; then
warn "MTU size is $MTU, but cannot be set for $ADAPTER adapters!" && MTU="0"
fi
fi
@ -708,6 +722,7 @@ getInfo() {
# Generate MAC address based on Docker container ID in hostname
VM_NET_MAC=$(echo "$HOST" | md5sum | sed 's/^\(..\)\(..\)\(..\)\(..\)\(..\).*$/02:11:32:\3:\4:\5/')
echo "${VM_NET_MAC^^}" > "$file"
! setOwner "$file" && error "Failed to set the owner for \"$file\" !"
fi
fi
@ -725,13 +740,6 @@ getInfo() {
GATEWAY_MAC=$(echo "$VM_NET_MAC" | md5sum | sed 's/^\(..\)\(..\)\(..\)\(..\)\(..\).*$/02:\1:\2:\3:\4:\5/')
if [[ "$PODMAN" == [Yy1]* && "$DHCP" != [Yy1]* ]]; then
if [ -z "$NETWORK" ] || [[ "${NETWORK^^}" == "Y" ]]; then
# By default Podman has no permissions for NAT networking
NETWORK="user"
fi
fi
if [[ "$DEBUG" == [Yy1]* ]]; then
line="Host: $HOST IP: $IP Gateway: $GATEWAY Interface: $VM_NET_DEV MAC: $VM_NET_MAC MTU: $mtu"
[[ "$MTU" != "0" && "$MTU" != "$mtu" ]] && line+=" ($MTU)"
@ -785,26 +793,28 @@ else
fi
case "${NETWORK,,}" in
"user"* | "passt" | "slirp" ) ;;
"nat" | "tap" | "tun" | "tuntap" | "y" )
"passt" | "slirp" | "user"* ) ;;
"tap" | "tun" | "tuntap" | "y" )
# Configure tap interface
if ! configureNAT; then
closeBridge
NETWORK="user"
msg="falling back to user-mode networking!"
msg="failed to setup NAT networking, $msg"
if [[ "$PODMAN" != [Yy1]* ]]; then
msg="falling back to user-mode networking!"
msg="failed to setup NAT networking, $msg"
warn "$msg"
fi
fi ;;
esac
[[ "${NETWORK,,}" == "user"* ]] && NETWORK="passt"
case "${NETWORK,,}" in
"nat" | "tap" | "tun" | "tuntap" | "y" ) ;;
"passt" )
"tap" | "tun" | "tuntap" | "y" ) ;;
"passt" | "user"* )
# Configure for user-mode networking (passt)
if ! configurePasst; then
@ -828,7 +838,7 @@ else
"passt" | "slirp" )
if [ -z "$USER_PORTS" ]; then
info "Notice: because user-mode networking is active, if you need to expose ports, add them to the \"USER_PORTS\" variable."
info "Notice: because user-mode networking is active, when you need to forward custom ports to DSM, add them to the \"USER_PORTS\" variable."
fi ;;
esac

View File

@ -33,6 +33,7 @@ _trap() {
finish() {
local pid
local cnt=0
local reason=$1
touch "$QEMU_END"
@ -40,14 +41,24 @@ finish() {
if [ -s "$QEMU_PID" ]; then
pid=$(<"$QEMU_PID")
echo && error "Forcefully terminating QEMU process, reason: $reason..."
echo && error "Forcefully terminating Virtual DSM, reason: $reason..."
{ kill -15 "$pid" || true; } 2>/dev/null
while isAlive "$pid"; do
sleep 1
cnt=$((cnt+1))
# Workaround for zombie pid
[ ! -s "$QEMU_PID" ] && break
if [ "$cnt" == "5" ]; then
echo && error "QEMU did not terminate itself, forcefully killing process..."
{ kill -9 "$pid" || true; } 2>/dev/null
fi
done
fi
fKill "print.sh"

View File

@ -33,9 +33,8 @@ if [[ "$KVM" != [Nn]* ]]; then
KVM_OPTS=",accel=kvm -enable-kvm -global kvm-pit.lost_tick_policy=discard"
if ! grep -qw "sse4_2" <<< "$flags"; then
info "Your CPU does not have the SSE4 instruction set that Virtual DSM requires, it will be emulated..."
[ -z "$CPU_MODEL" ] && CPU_MODEL="qemu64"
CPU_FEATURES+=",+ssse3,+sse4.1,+sse4.2"
error "Your CPU does not have the SSE4 instruction set that Virtual DSM requires!"
[[ "$DEBUG" != [Yy1]* ]] && exit 88
fi
if [ -z "$CPU_MODEL" ]; then

View File

@ -1,6 +1,8 @@
#!/usr/bin/env bash
set -Eeuo pipefail
info="/run/shm/msg.html"
escape () {
local s
s=${1//&/\&amp;}
@ -11,28 +13,33 @@ escape () {
return 0
}
file="$1"
path="$1"
total="$2"
body=$(escape "$3")
info="/run/shm/msg.html"
if [[ "$body" == *"..." ]]; then
body="<p class=\"loading\">${body/.../}</p>"
body="<p class=\"loading\">${body::-3}</p>"
fi
while true
do
if [ -s "$file" ]; then
bytes=$(du -sb "$file" | cut -f1)
if (( bytes > 1000 )); then
if [ -z "$total" ] || [[ "$total" == "0" ]] || [ "$bytes" -gt "$total" ]; then
size=$(numfmt --to=iec --suffix=B "$bytes" | sed -r 's/([A-Z])/ \1/')
else
size="$(echo "$bytes" "$total" | awk '{printf "%.1f", $1 * 100 / $2}')"
size="$size%"
fi
echo "${body//(\[P\])/($size)}"> "$info"
fi
if [ ! -s "$path" ] && [ ! -d "$path" ]; then
bytes="0"
else
bytes=$(du -sb "$path" | cut -f1)
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/')
else
size="$(echo "$bytes" "$total" | awk '{printf "%.1f", $1 * 100 / $2}')"
size="$size%"
fi
[[ "$size" != "0.0%" ]] && echo "${body//(\[P\])/($size)}"> "$info"
fi
sleep 1 & wait $!
done

View File

@ -59,6 +59,8 @@ fi
CPU_CORES="${CPU_CORES// /}"
[[ "${CPU_CORES,,}" == "max" ]] && CPU_CORES="$CORES"
[[ "${CPU_CORES,,}" == "half" ]] && CPU_CORES=$(( CORES / 2 ))
[[ "${CPU_CORES,,}" == "0" ]] && CPU_CORES="1"
[ -n "${CPU_CORES//[0-9 ]}" ] && error "Invalid amount of CPU_CORES: $CPU_CORES" && exit 15
if [ "$CPU_CORES" -gt "$CORES" ]; then
@ -76,8 +78,7 @@ fi
# Check folder
if [[ "${COMMIT:-}" == [Yy1]* ]]; then
STORAGE="/local"
if [[ "${STORAGE,,}" != "/storage" ]]; then
mkdir -p "$STORAGE"
fi
@ -86,7 +87,9 @@ if [ ! -d "$STORAGE" ]; then
fi
if [ ! -w "$STORAGE" ]; then
error "Storage folder ($STORAGE) is not writeable!" && exit 13
msg="Storage folder ($STORAGE) is not writeable!"
msg+=" If SELinux is active, you need to add the \":Z\" flag to the bind mount."
error "$msg" && exit 13
fi
# Check filesystem
@ -105,20 +108,18 @@ RAM_TOTAL=$(free -b | grep -m 1 Mem: | awk '{print $2}')
RAM_SIZE="${RAM_SIZE// /}"
[ -z "$RAM_SIZE" ] && error "RAM_SIZE not specified!" && exit 16
if [[ "${RAM_SIZE,,}" == "max" ]]; then
RAM_WANTED=$(( RAM_AVAIL - RAM_SPARE - RAM_SPARE ))
RAM_WANTED=$(( RAM_WANTED / 1073741825 ))
RAM_SIZE="${RAM_WANTED}G"
fi
if [[ "${RAM_SIZE,,}" != "max" && "${RAM_SIZE,,}" != "half" ]]; then
if [ -z "${RAM_SIZE//[0-9. ]}" ]; then
[ "${RAM_SIZE%%.*}" -lt "130" ] && RAM_SIZE="${RAM_SIZE}G" || RAM_SIZE="${RAM_SIZE}M"
fi
if [ -z "${RAM_SIZE//[0-9. ]}" ]; then
[ "${RAM_SIZE%%.*}" -lt "130" ] && RAM_SIZE="${RAM_SIZE}G" || RAM_SIZE="${RAM_SIZE}M"
fi
RAM_SIZE=$(echo "${RAM_SIZE^^}" | sed 's/MB/M/g;s/GB/G/g;s/TB/T/g')
! numfmt --from=iec "$RAM_SIZE" &>/dev/null && error "Invalid RAM_SIZE: $RAM_SIZE" && exit 16
RAM_WANTED=$(numfmt --from=iec "$RAM_SIZE")
[ "$RAM_WANTED" -lt "136314880 " ] && error "RAM_SIZE is too low: $RAM_SIZE" && exit 16
RAM_SIZE=$(echo "${RAM_SIZE^^}" | sed 's/MB/M/g;s/GB/G/g;s/TB/T/g')
! numfmt --from=iec "$RAM_SIZE" &>/dev/null && error "Invalid RAM_SIZE: $RAM_SIZE" && exit 16
RAM_WANTED=$(numfmt --from=iec "$RAM_SIZE")
[ "$RAM_WANTED" -lt "136314880 " ] && error "RAM_SIZE is too low: $RAM_SIZE" && exit 16
fi
# Print system info
SYS="${SYS/-generic/}"
@ -133,15 +134,6 @@ TOTAL_MEM=$(formatBytes "$RAM_TOTAL" "up")
echo " CPU: ${CPU} | RAM: ${AVAIL_MEM/ GB/}/$TOTAL_MEM | DISK: $SPACE_GB (${FS}) | KERNEL: ${SYS}..."
echo
# Check available memory
if [[ "$RAM_CHECK" != [Nn]* ]] && (( (RAM_WANTED + RAM_SPARE) > RAM_AVAIL )); then
AVAIL_MEM=$(formatBytes "$RAM_AVAIL")
msg="Your configured RAM_SIZE of ${RAM_SIZE/G/ GB} is too high for the $AVAIL_MEM of memory available, please set a lower value."
[[ "${FS,,}" != "zfs" ]] && error "$msg" && exit 17
info "$msg"
fi
# Check KVM support
if [[ "${PLATFORM,,}" == "x64" ]]; then
@ -174,6 +166,10 @@ if [[ "$KVM" != [Nn]* ]]; then
if ! grep -qw "vmx\|svm" <<< "$flags"; then
KVM_ERR="(not enabled in BIOS)"
fi
if ! grep -qw "sse4_2" <<< "$flags"; then
error "Your CPU does not have the SSE4 instruction set that Virtual DSM requires!"
[[ "$DEBUG" != [Yy1]* ]] && exit 88
fi
fi
fi
fi

View File

@ -1,16 +1,31 @@
#!/usr/bin/env bash
set -Eeuo pipefail
lastmsg=""
path="/run/shm/msg.html"
if [ -f "$path" ] && [ -s "$path" ]; then
echo -n "s: " && cat "$path"
fi
refresh() {
[ ! -f "$path" ] && return 0
[ ! -s "$path" ] && return 0
msg=$(< "$path")
msg="${msg%$'\n'}"
[ -z "$msg" ] && return 0
[[ "$msg" == "$lastmsg" ]] && return 0
lastmsg="$msg"
echo "s: $msg"
return 0
}
refresh
inotifywait -m "$path" |
while read -r fp event fn; do
case "${event,,}" in
"modify"* ) echo -n "s: " && cat "$path" ;;
"modify"* ) refresh ;;
"delete_self" ) echo "c: vnc" ;;
esac
done

View File

@ -67,6 +67,37 @@ fKill() {
return 0
}
setOwner() {
local file="$1"
local dir uid gid
[ ! -f "$file" ] && return 1
dir=$(dirname -- "$file")
uid=$(stat -c '%u' "$dir")
gid=$(stat -c '%g' "$dir")
! chown "$uid:$gid" "$file" && return 1
return 0
}
makeDir() {
local path="$1"
local dir uid gid
[ -d "$path" ] && return 0
! mkdir -p "$path" && return 1
dir=$(dirname -- "$path")
uid=$(stat -c '%u' "$dir")
gid=$(stat -c '%g' "$dir")
! chown "$uid:$gid" "$path" && return 1
return 0
}
escape () {
local s
s=${1//&/\&amp;}
@ -123,11 +154,11 @@ cpu() {
fi
cpu="${cpu// CPU/}"
cpu="${cpu// [0-9] Core}"
cpu="${cpu// [0-9][0-9] Core}"
cpu="${cpu// [0-9][0-9][0-9] Core}"
cpu="${cpu//[0-9]th Gen }"
cpu="${cpu// [0-9][0-9] Core}"
cpu="${cpu// [0-9] Core}"
cpu="${cpu//[0-9][0-9]th Gen }"
cpu="${cpu//[0-9]th Gen }"
cpu="${cpu// Processor/}"
cpu="${cpu// Quad core/}"
cpu="${cpu// Dual core/}"