mirror of
https://github.com/vdsm/virtual-dsm.git
synced 2025-11-07 18:43:41 +08:00
Compare commits
43 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a70338ec3c | ||
|
|
a84878abfc | ||
|
|
8421a391b7 | ||
|
|
f9340ec3d6 | ||
|
|
0cca9c5f83 | ||
|
|
13d60b7f47 | ||
|
|
f74771a9cc | ||
|
|
f24ba41930 | ||
|
|
f412580a4a | ||
|
|
5cde1b4438 | ||
|
|
7cfb57b1bc | ||
|
|
a478b58f97 | ||
|
|
8297f4f880 | ||
|
|
4c67343d33 | ||
|
|
53cc6998f0 | ||
|
|
d857d71e0d | ||
|
|
003c2766ce | ||
|
|
78594098cc | ||
|
|
3c31bc91e4 | ||
|
|
72141bab7a | ||
|
|
bc52463aa4 | ||
|
|
9fa68908a9 | ||
|
|
740dbec1b1 | ||
|
|
440d203730 | ||
|
|
1a83c67e2c | ||
|
|
34a707a2a5 | ||
|
|
cabb2cdfc9 | ||
|
|
dc52ccf172 | ||
|
|
bdd7fec3c3 | ||
|
|
bd8b03d089 | ||
|
|
a10588b0ce | ||
|
|
3503b86e12 | ||
|
|
9e124980cd | ||
|
|
675aa5e122 | ||
|
|
2a62d4e938 | ||
|
|
9cbb51cc86 | ||
|
|
7790f81d15 | ||
|
|
fdbff4879b | ||
|
|
739e679a66 | ||
|
|
0dea507d85 | ||
|
|
4f524c47d8 | ||
|
|
0c74201eb4 | ||
|
|
1e13258bc9 |
16
.github/workflows/build.yml
vendored
16
.github/workflows/build.yml
vendored
@@ -8,6 +8,10 @@ on:
|
|||||||
paths-ignore:
|
paths-ignore:
|
||||||
- '**/*.md'
|
- '**/*.md'
|
||||||
- '**/*.yml'
|
- '**/*.yml'
|
||||||
|
- '**/*.js'
|
||||||
|
- '**/*.css'
|
||||||
|
- '**/*.html'
|
||||||
|
- 'web/**'
|
||||||
- '.gitignore'
|
- '.gitignore'
|
||||||
- '.dockerignore'
|
- '.dockerignore'
|
||||||
- '.github/**'
|
- '.github/**'
|
||||||
@@ -99,3 +103,15 @@ jobs:
|
|||||||
url: ${{ secrets.GITLAB_URL }}
|
url: ${{ secrets.GITLAB_URL }}
|
||||||
token: ${{ secrets.GITLAB_TOKEN }}
|
token: ${{ secrets.GITLAB_TOKEN }}
|
||||||
username: ${{ secrets.GITLAB_USERNAME }}
|
username: ${{ secrets.GITLAB_USERNAME }}
|
||||||
|
-
|
||||||
|
name: Send mail
|
||||||
|
uses: action-pack/send-mail@v1
|
||||||
|
with:
|
||||||
|
to: ${{secrets.MAILTO}}
|
||||||
|
from: Github Actions <${{secrets.MAILTO}}>
|
||||||
|
connection_url: ${{secrets.MAIL_CONNECTION}}
|
||||||
|
subject: Build of ${{ github.event.repository.name }} v${{ steps.meta.outputs.version }} completed
|
||||||
|
body: |
|
||||||
|
The build job of ${{ github.event.repository.name }} v${{ steps.meta.outputs.version }} was completed successfully!
|
||||||
|
|
||||||
|
See https://github.com/${{ github.repository }}/actions for more information.
|
||||||
|
|||||||
14
.github/workflows/check.yml
vendored
14
.github/workflows/check.yml
vendored
@@ -7,8 +7,18 @@ jobs:
|
|||||||
name: shellcheck
|
name: shellcheck
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
-
|
||||||
- name: Run ShellCheck
|
name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
-
|
||||||
|
name: Run ShellCheck
|
||||||
uses: ludeeus/action-shellcheck@master
|
uses: ludeeus/action-shellcheck@master
|
||||||
env:
|
env:
|
||||||
SHELLCHECK_OPTS: -x --source-path=src -e SC2001 -e SC2034 -e SC2064 -e SC2317 -e SC2153 -e SC2028
|
SHELLCHECK_OPTS: -x --source-path=src -e SC2001 -e SC2034 -e SC2064 -e SC2317 -e SC2153 -e SC2028
|
||||||
|
-
|
||||||
|
name: Lint Dockerfile
|
||||||
|
uses: hadolint/hadolint-action@v3.1.0
|
||||||
|
with:
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
ignore: DL3008,DL3003,DL3006
|
||||||
|
failure-threshold: warning
|
||||||
|
|||||||
2
.github/workflows/hub.yml
vendored
2
.github/workflows/hub.yml
vendored
@@ -15,7 +15,7 @@ jobs:
|
|||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
-
|
-
|
||||||
name: Docker Hub Description
|
name: Docker Hub Description
|
||||||
uses: peter-evans/dockerhub-description@v3
|
uses: peter-evans/dockerhub-description@v4
|
||||||
with:
|
with:
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
|||||||
1
.github/workflows/test.yml
vendored
1
.github/workflows/test.yml
vendored
@@ -3,6 +3,7 @@ on:
|
|||||||
pull_request:
|
pull_request:
|
||||||
paths:
|
paths:
|
||||||
- '**/*.sh'
|
- '**/*.sh'
|
||||||
|
- 'Dockerfile'
|
||||||
- '.github/workflows/test.yml'
|
- '.github/workflows/test.yml'
|
||||||
- '.github/workflows/check.yml'
|
- '.github/workflows/check.yml'
|
||||||
|
|
||||||
|
|||||||
18
readme.md
18
readme.md
@@ -1,6 +1,6 @@
|
|||||||
<h1 align="center">Virtual DSM<br />
|
<h1 align="center">Virtual DSM<br />
|
||||||
<div align="center">
|
<div align="center">
|
||||||
<img src="https://github.com/vdsm/virtual-dsm/raw/master/.github/screen.jpg" title="Screenshot" style="max-width:100%;" width="432" />
|
<a href="https://github.com/vdsm/virtual-dsm"><img src="https://github.com/vdsm/virtual-dsm/raw/master/.github/screen.jpg" title="Screenshot" style="max-width:100%;" width="432" /></a>
|
||||||
</div>
|
</div>
|
||||||
<div align="center">
|
<div align="center">
|
||||||
|
|
||||||
@@ -17,7 +17,6 @@ Virtual DSM in a docker container.
|
|||||||
|
|
||||||
- Multiple disks
|
- Multiple disks
|
||||||
- KVM acceleration
|
- KVM acceleration
|
||||||
- GPU pass-through
|
|
||||||
- Upgrades supported
|
- Upgrades supported
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
@@ -47,7 +46,7 @@ services:
|
|||||||
Via `docker run`
|
Via `docker run`
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker run -it --rm -p 5000:5000 --device=/dev/kvm --cap-add NET_ADMIN --stop-timeout 60 vdsm/virtual-dsm
|
docker run -it --rm -p 5000:5000 --device=/dev/kvm --cap-add NET_ADMIN --stop-timeout 120 vdsm/virtual-dsm
|
||||||
```
|
```
|
||||||
|
|
||||||
## FAQ
|
## FAQ
|
||||||
@@ -56,13 +55,11 @@ docker run -it --rm -p 5000:5000 --device=/dev/kvm --cap-add NET_ADMIN --stop-ti
|
|||||||
|
|
||||||
Very simple! These are the steps:
|
Very simple! These are the steps:
|
||||||
|
|
||||||
- Start the container and get some coffee.
|
- Start the container and connect to [port 5000](http://localhost:5000) using your web browser.
|
||||||
|
|
||||||
- Connect to port 5000 of the container in your web browser.
|
|
||||||
|
|
||||||
- Wait until DSM is ready, choose an username and password, and you will be taken to the desktop.
|
- Wait until DSM is ready, choose an username and password, and you will be taken to the desktop.
|
||||||
|
|
||||||
- Enjoy your brand new machine, and don't forget to star this repo!
|
Enjoy your brand new machine, and don't forget to star this repo!
|
||||||
|
|
||||||
* ### How do I change the size of the disk?
|
* ### How do I change the size of the disk?
|
||||||
|
|
||||||
@@ -192,7 +189,7 @@ docker run -it --rm -p 5000:5000 --device=/dev/kvm --cap-add NET_ADMIN --stop-ti
|
|||||||
|
|
||||||
After configuring the container for macvlan (see above), it is possible for DSM to become part of your home network by requesting an IP from your router, just like your other devices.
|
After configuring the container for macvlan (see above), it is possible for DSM to become part of your home network by requesting an IP from your router, just like your other devices.
|
||||||
|
|
||||||
To enable this feature, add the following lines to your compose file:
|
To enable this mode, add the following lines to your compose file:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
environment:
|
environment:
|
||||||
@@ -201,7 +198,7 @@ docker run -it --rm -p 5000:5000 --device=/dev/kvm --cap-add NET_ADMIN --stop-ti
|
|||||||
- 'c *:* rwm'
|
- 'c *:* rwm'
|
||||||
```
|
```
|
||||||
|
|
||||||
Please note that even if you don't want DHCP, it's still recommended to enable this feature, as it prevents NAT issues and increases performance by using a `macvtap` interface. In that case, just set a static IP from the DSM control panel after you enabled this mode.
|
Please note that even if you don't need DHCP, it's still recommended to enable this mode, as it prevents NAT issues and increases performance by using a `macvtap` interface. You can just set a static IP from the DSM control panel afterwards.
|
||||||
|
|
||||||
* ### How do I pass-through the GPU?
|
* ### How do I pass-through the GPU?
|
||||||
|
|
||||||
@@ -237,6 +234,9 @@ docker run -it --rm -p 5000:5000 --device=/dev/kvm --cap-add NET_ADMIN --stop-ti
|
|||||||
|
|
||||||
However, by installing Synology's Virtual DSM, you must accept their end-user license agreement, which does not permit installation on non-Synology hardware. So only run this project on an official Synology NAS, as any other use will be a violation of their terms and conditions.
|
However, by installing Synology's Virtual DSM, you must accept their end-user license agreement, which does not permit installation on non-Synology hardware. So only run this project on an official Synology NAS, as any other use will be a violation of their terms and conditions.
|
||||||
|
|
||||||
|
## Stars
|
||||||
|
[](https://starchart.cc/vdsm/virtual-dsm)
|
||||||
|
|
||||||
## Disclaimer
|
## Disclaimer
|
||||||
|
|
||||||
Only run this container on Synology hardware, any other use is not permitted by their EULA. The product names, logos, brands, and other trademarks referred to within this project are the property of their respective trademark holders. This project is not affiliated, sponsored, or endorsed by Synology, Inc.
|
Only run this container on Synology hardware, any other use is not permitted by their EULA. The product names, logos, brands, and other trademarks referred to within this project are the property of their respective trademark holders. This project is not affiliated, sponsored, or endorsed by Synology, Inc.
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ set -Eeuo pipefail
|
|||||||
|
|
||||||
DEF_OPTS="-nodefaults -boot strict=on"
|
DEF_OPTS="-nodefaults -boot strict=on"
|
||||||
RAM_OPTS=$(echo "-m $RAM_SIZE" | sed 's/MB/M/g;s/GB/G/g;s/TB/T/g')
|
RAM_OPTS=$(echo "-m $RAM_SIZE" | sed 's/MB/M/g;s/GB/G/g;s/TB/T/g')
|
||||||
CPU_OPTS="-cpu $CPU_MODEL -smp $CPU_CORES,sockets=1,dies=1,cores=$CPU_CORES,threads=1"
|
CPU_OPTS="-cpu $CPU_FLAGS -smp $CPU_CORES,sockets=1,dies=1,cores=$CPU_CORES,threads=1"
|
||||||
MAC_OPTS="-machine type=q35,usb=off,dump-guest-core=off,hpet=off${KVM_OPTS}"
|
MAC_OPTS="-machine type=q35,usb=off,vmport=off,dump-guest-core=off,hpet=off${KVM_OPTS}"
|
||||||
DEV_OPTS="-device virtio-balloon-pci,id=balloon0,bus=pcie.0,addr=0x4"
|
DEV_OPTS="-device virtio-balloon-pci,id=balloon0,bus=pcie.0,addr=0x4"
|
||||||
DEV_OPTS="$DEV_OPTS -object rng-random,id=objrng0,filename=/dev/urandom"
|
DEV_OPTS="$DEV_OPTS -object rng-random,id=objrng0,filename=/dev/urandom"
|
||||||
DEV_OPTS="$DEV_OPTS -device virtio-rng-pci,rng=objrng0,id=rng0,bus=pcie.0,addr=0x1c"
|
DEV_OPTS="$DEV_OPTS -device virtio-rng-pci,rng=objrng0,id=rng0,bus=pcie.0,addr=0x1c"
|
||||||
|
|||||||
44
src/disk.sh
44
src/disk.sh
@@ -80,7 +80,7 @@ getSize() {
|
|||||||
isCow() {
|
isCow() {
|
||||||
local FS=$1
|
local FS=$1
|
||||||
|
|
||||||
if [[ "${FS,,}" == "xfs" || "${FS,,}" == "zfs" || "${FS,,}" == "btrfs" || "${FS,,}" == "bcachefs" ]]; then
|
if [[ "${FS,,}" == "btrfs" ]]; then
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -112,8 +112,8 @@ createDisk() {
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
MSG="Creating a $DISK_TYPE $DISK_DESC image in $DISK_FMT format with a size of $DISK_SPACE..."
|
html "Creating a $DISK_DESC image..."
|
||||||
info "$MSG" && html "$MSG"
|
info "Creating a $DISK_SPACE $DISK_TYPE $DISK_DESC image in $DISK_FMT format..."
|
||||||
|
|
||||||
local FAIL="Could not create a $DISK_TYPE $DISK_FMT $DISK_DESC image of $DISK_SPACE ($DISK_FILE)"
|
local FAIL="Could not create a $DISK_TYPE $DISK_FMT $DISK_DESC image of $DISK_SPACE ($DISK_FILE)"
|
||||||
|
|
||||||
@@ -266,8 +266,8 @@ convertDisk() {
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
MSG="Converting $DISK_DESC to $DST_FMT, please wait until completed..."
|
html "Converting $DISK_DESC to $DST_FMT..."
|
||||||
info "$MSG" && html "$MSG"
|
info "Converting $DISK_DESC to $DST_FMT, please wait until completed..."
|
||||||
|
|
||||||
local CONV_FLAGS="-p"
|
local CONV_FLAGS="-p"
|
||||||
local DISK_PARAM="$DISK_ALLOC"
|
local DISK_PARAM="$DISK_ALLOC"
|
||||||
@@ -306,8 +306,8 @@ convertDisk() {
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
MSG="Conversion of $DISK_DESC to $DST_FMT completed succesfully!"
|
html "Conversion of $DISK_DESC completed..."
|
||||||
info "$MSG" && html "$MSG"
|
info "Conversion of $DISK_DESC to $DST_FMT completed succesfully!"
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
@@ -341,6 +341,21 @@ checkFS () {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
createDevice () {
|
||||||
|
|
||||||
|
local DISK_ID=$1
|
||||||
|
local DISK_FILE=$2
|
||||||
|
local DISK_INDEX=$3
|
||||||
|
local DISK_ADDRESS=$4
|
||||||
|
local DISK_FMT=$5
|
||||||
|
|
||||||
|
echo "-drive file=$DISK_FILE,if=none,id=drive-$DISK_ID,format=$DISK_FMT,cache=$DISK_CACHE,aio=$DISK_IO,discard=$DISK_DISCARD,detect-zeroes=on \
|
||||||
|
-device virtio-scsi-pci,id=hw-$DISK_ID,iothread=io2,bus=pcie.0,addr=$DISK_ADDRESS \
|
||||||
|
-device scsi-hd,bus=hw-$DISK_ID.0,channel=0,scsi-id=0,lun=0,drive=drive-$DISK_ID,id=$DISK_ID,rotation_rate=$DISK_ROTATION,bootindex=$DISK_INDEX"
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
addDisk () {
|
addDisk () {
|
||||||
local DISK_ID=$1
|
local DISK_ID=$1
|
||||||
local DISK_BASE=$2
|
local DISK_BASE=$2
|
||||||
@@ -351,7 +366,7 @@ addDisk () {
|
|||||||
local DISK_ADDRESS=$7
|
local DISK_ADDRESS=$7
|
||||||
local DISK_FMT=$8
|
local DISK_FMT=$8
|
||||||
local DISK_FILE="$DISK_BASE.$DISK_EXT"
|
local DISK_FILE="$DISK_BASE.$DISK_EXT"
|
||||||
local DIR DATA_SIZE FS PREV_FMT PREV_EXT CUR_SIZE
|
local DIR DATA_SIZE FS PREV_FMT PREV_EXT CUR_SIZE OPTS
|
||||||
|
|
||||||
DIR=$(dirname "$DISK_FILE")
|
DIR=$(dirname "$DISK_FILE")
|
||||||
[ ! -d "$DIR" ] && return 0
|
[ ! -d "$DIR" ] && return 0
|
||||||
@@ -399,10 +414,8 @@ addDisk () {
|
|||||||
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
DISK_OPTS="$DISK_OPTS \
|
OPTS=$(createDevice "$DISK_ID" "$DISK_FILE" "$DISK_INDEX" "$DISK_ADDRESS" "$DISK_FMT")
|
||||||
-device virtio-scsi-pci,id=hw-$DISK_ID,iothread=io2,bus=pcie.0,addr=$DISK_ADDRESS \
|
DISK_OPTS="$DISK_OPTS $OPTS"
|
||||||
-drive file=$DISK_FILE,if=none,id=drive-$DISK_ID,format=$DISK_FMT,cache=$DISK_CACHE,aio=$DISK_IO,discard=$DISK_DISCARD,detect-zeroes=on \
|
|
||||||
-device scsi-hd,bus=hw-$DISK_ID.0,channel=0,scsi-id=0,lun=0,drive=drive-$DISK_ID,id=$DISK_ID,rotation_rate=$DISK_ROTATION,bootindex=$DISK_INDEX"
|
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
@@ -418,10 +431,9 @@ addDevice () {
|
|||||||
[ -z "$DISK_DEV" ] && return 0
|
[ -z "$DISK_DEV" ] && return 0
|
||||||
[ ! -b "$DISK_DEV" ] && error "Device $DISK_DEV cannot be found! Please add it to the 'devices' section of your compose file." && exit 55
|
[ ! -b "$DISK_DEV" ] && error "Device $DISK_DEV cannot be found! Please add it to the 'devices' section of your compose file." && exit 55
|
||||||
|
|
||||||
DISK_OPTS="$DISK_OPTS \
|
local OPTS
|
||||||
-device virtio-scsi-pci,id=hw-$DISK_ID,iothread=io2,bus=pcie.0,addr=$DISK_ADDRESS \
|
OPTS=$(createDevice "$DISK_ID" "$DISK_DEV" "$DISK_INDEX" "$DISK_ADDRESS" "raw")
|
||||||
-drive file=$DISK_DEV,if=none,id=drive-$DISK_ID,format=raw,cache=$DISK_CACHE,aio=$DISK_IO,discard=$DISK_DISCARD,detect-zeroes=on \
|
DISK_OPTS="$DISK_OPTS $OPTS"
|
||||||
-device scsi-hd,bus=hw-$DISK_ID.0,channel=0,scsi-id=0,lun=0,drive=drive-$DISK_ID,id=$DISK_ID,rotation_rate=$DISK_ROTATION,bootindex=$DISK_INDEX"
|
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,8 @@ if [[ "$GPU" != [Yy1]* ]] || [[ "$ARCH" != "amd64" ]]; then
|
|||||||
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
DISPLAY_OPTS="-display egl-headless,rendernode=/dev/dri/renderD128 -vga $VGA"
|
DISPLAY_OPTS="-display egl-headless,rendernode=/dev/dri/renderD128"
|
||||||
|
DISPLAY_OPTS="$DISPLAY_OPTS -vga $VGA"
|
||||||
|
|
||||||
[ ! -d /dev/dri ] && mkdir -m 755 /dev/dri
|
[ ! -d /dev/dri ] && mkdir -m 755 /dev/dri
|
||||||
|
|
||||||
|
|||||||
@@ -18,11 +18,13 @@ cd /run
|
|||||||
|
|
||||||
trap - ERR
|
trap - ERR
|
||||||
|
|
||||||
|
info "Booting $APP using $VERS..."
|
||||||
|
[[ "$DEBUG" == [Yy1]* ]] && echo "Arguments: $ARGS" && echo
|
||||||
|
|
||||||
if [[ "$CONSOLE" == [Yy]* ]]; then
|
if [[ "$CONSOLE" == [Yy]* ]]; then
|
||||||
exec qemu-system-x86_64 ${ARGS:+ $ARGS}
|
exec qemu-system-x86_64 ${ARGS:+ $ARGS}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
[[ "$DEBUG" == [Yy1]* ]] && info "$VERS" && echo "Arguments: $ARGS" && echo
|
|
||||||
{ qemu-system-x86_64 ${ARGS:+ $ARGS} >"$QEMU_OUT" 2>"$QEMU_LOG"; rc=$?; } || :
|
{ qemu-system-x86_64 ${ARGS:+ $ARGS} >"$QEMU_OUT" 2>"$QEMU_LOG"; rc=$?; } || :
|
||||||
(( rc != 0 )) && error "$(<"$QEMU_LOG")" && exit 15
|
(( rc != 0 )) && error "$(<"$QEMU_LOG")" && exit 15
|
||||||
|
|
||||||
|
|||||||
@@ -65,7 +65,11 @@ if [[ "${FS,,}" == "fuse"* ]]; then
|
|||||||
info "Warning: the filesystem of $STORAGE is FUSE, this extra layer will negatively affect performance!"
|
info "Warning: the filesystem of $STORAGE is FUSE, this extra layer will negatively affect performance!"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "${FS,,}" != "fat"* && "${FS,,}" != "vfat"* && "${FS,,}" != "exfat"* && "${FS,,}" != "ntfs"* && "${FS,,}" != "msdos"* ]]; then
|
if [[ "${FS,,}" == "fat"* || "${FS,,}" == "vfat"* || "${FS,,}" == "msdos"* ]]; then
|
||||||
|
error "Unable to install on $FS filesystems, please use a different filesystem for /storage." && exit 61
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "${FS,,}" != "exfat"* && "${FS,,}" != "ntfs"* && "${FS,,}" != "unknown"* ]]; then
|
||||||
TMP="$STORAGE/tmp"
|
TMP="$STORAGE/tmp"
|
||||||
else
|
else
|
||||||
TMP="/tmp/dsm"
|
TMP="/tmp/dsm"
|
||||||
@@ -105,6 +109,7 @@ RDC="$STORAGE/dsm.rd"
|
|||||||
if [ ! -f "$RDC" ]; then
|
if [ ! -f "$RDC" ]; then
|
||||||
|
|
||||||
MSG="Downloading installer..."
|
MSG="Downloading installer..."
|
||||||
|
PRG="Downloading installer ([P])..."
|
||||||
info "Install: $MSG" && html "$MSG"
|
info "Install: $MSG" && html "$MSG"
|
||||||
|
|
||||||
RD="$TMP/rd.gz"
|
RD="$TMP/rd.gz"
|
||||||
@@ -112,7 +117,11 @@ if [ ! -f "$RDC" ]; then
|
|||||||
VERIFY="b4215a4b213ff5154db0488f92c87864"
|
VERIFY="b4215a4b213ff5154db0488f92c87864"
|
||||||
LOC="$DL/release/7.0.1/42218/DSM_VirtualDSM_42218.pat"
|
LOC="$DL/release/7.0.1/42218/DSM_VirtualDSM_42218.pat"
|
||||||
|
|
||||||
|
rm -f "$RD"
|
||||||
|
/run/progress.sh "$RD" "$PRG" &
|
||||||
{ curl -r "$POS" -sfk -S -o "$RD" "$LOC"; rc=$?; } || :
|
{ curl -r "$POS" -sfk -S -o "$RD" "$LOC"; rc=$?; } || :
|
||||||
|
|
||||||
|
fKill "progress.sh"
|
||||||
(( rc != 0 )) && error "Failed to download $LOC, reason: $rc" && exit 60
|
(( rc != 0 )) && error "Failed to download $LOC, reason: $rc" && exit 60
|
||||||
|
|
||||||
SUM=$(md5sum "$RD" | cut -f 1 -d " ")
|
SUM=$(md5sum "$RD" | cut -f 1 -d " ")
|
||||||
@@ -123,7 +132,11 @@ if [ ! -f "$RDC" ]; then
|
|||||||
rm "$RD"
|
rm "$RD"
|
||||||
rm -f "$PAT"
|
rm -f "$PAT"
|
||||||
|
|
||||||
|
html "$MSG"
|
||||||
|
/run/progress.sh "$PAT" "$PRG" &
|
||||||
{ wget "$LOC" -O "$PAT" -q --no-check-certificate --show-progress "$PROGRESS"; rc=$?; } || :
|
{ wget "$LOC" -O "$PAT" -q --no-check-certificate --show-progress "$PROGRESS"; rc=$?; } || :
|
||||||
|
|
||||||
|
fKill "progress.sh"
|
||||||
(( rc != 0 )) && error "Failed to download $LOC , reason: $rc" && exit 60
|
(( rc != 0 )) && error "Failed to download $LOC , reason: $rc" && exit 60
|
||||||
|
|
||||||
tar --extract --file="$PAT" --directory="$(dirname "$RD")"/. "$(basename "$RD")"
|
tar --extract --file="$PAT" --directory="$(dirname "$RD")"/. "$(basename "$RD")"
|
||||||
@@ -138,14 +151,14 @@ fi
|
|||||||
if [ -f "$RDC" ]; then
|
if [ -f "$RDC" ]; then
|
||||||
|
|
||||||
{ xz -dc <"$RDC" >"$TMP/rd" 2>/dev/null; rc=$?; } || :
|
{ xz -dc <"$RDC" >"$TMP/rd" 2>/dev/null; rc=$?; } || :
|
||||||
(( rc != 1 )) && error "Failed to unxz $RDC, reason $rc" && exit 91
|
(( rc != 1 )) && error "Failed to unxz $RDC on $FS, reason $rc" && exit 91
|
||||||
|
|
||||||
{ (cd "$TMP" && cpio -idm <"$TMP/rd" 2>/dev/null); rc=$?; } || :
|
{ (cd "$TMP" && cpio -idm <"$TMP/rd" 2>/dev/null); rc=$?; } || :
|
||||||
|
|
||||||
if (( rc != 0 )); then
|
if (( rc != 0 )); then
|
||||||
ROOT="N"
|
ROOT="N"
|
||||||
{ (cd "$TMP" && fakeroot cpio -idmu <"$TMP/rd" 2>/dev/null); rc=$?; } || :
|
{ (cd "$TMP" && fakeroot cpio -idmu <"$TMP/rd" 2>/dev/null); rc=$?; } || :
|
||||||
(( rc != 0 )) && error "Failed to extract $RDC, reason $rc" && exit 92
|
(( rc != 0 )) && error "Failed to extract $RDC on $FS, reason $rc" && exit 92
|
||||||
fi
|
fi
|
||||||
|
|
||||||
rm -rf /run/extract && mkdir -p /run/extract
|
rm -rf /run/extract && mkdir -p /run/extract
|
||||||
@@ -174,8 +187,11 @@ fi
|
|||||||
|
|
||||||
rm -rf "$TMP" && mkdir -p "$TMP"
|
rm -rf "$TMP" && mkdir -p "$TMP"
|
||||||
|
|
||||||
MSG="Downloading $BASE.pat..."
|
info "Install: Downloading $BASE.pat..."
|
||||||
info "Install: $MSG" && html "$MSG"
|
|
||||||
|
MSG="Downloading DSM..."
|
||||||
|
PRG="Downloading DSM ([P])..."
|
||||||
|
html "$MSG"
|
||||||
|
|
||||||
PAT="/$BASE.pat"
|
PAT="/$BASE.pat"
|
||||||
rm -f "$PAT"
|
rm -f "$PAT"
|
||||||
@@ -186,7 +202,11 @@ if [[ "$URL" == "file://"* ]]; then
|
|||||||
|
|
||||||
else
|
else
|
||||||
|
|
||||||
|
/run/progress.sh "$PAT" "$PRG" &
|
||||||
|
|
||||||
{ wget "$URL" -O "$PAT" -q --no-check-certificate --show-progress "$PROGRESS"; rc=$?; } || :
|
{ wget "$URL" -O "$PAT" -q --no-check-certificate --show-progress "$PROGRESS"; rc=$?; } || :
|
||||||
|
|
||||||
|
fKill "progress.sh"
|
||||||
(( rc != 0 )) && error "Failed to download $URL , reason: $rc" && exit 69
|
(( rc != 0 )) && error "Failed to download $URL , reason: $rc" && exit 69
|
||||||
|
|
||||||
fi
|
fi
|
||||||
@@ -249,11 +269,11 @@ if ! touch "$SYSTEM"; then
|
|||||||
error "Could not create file $SYSTEM for the system disk." && exit 98
|
error "Could not create file $SYSTEM for the system disk." && exit 98
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "${FS,,}" == "xfs" || "${FS,,}" == "zfs" || "${FS,,}" == "btrfs" || "${FS,,}" == "bcachefs" ]]; then
|
if [[ "${FS,,}" == "btrfs" ]]; then
|
||||||
{ chattr +C "$SYSTEM"; } || :
|
{ chattr +C "$SYSTEM"; } || :
|
||||||
FA=$(lsattr "$SYSTEM")
|
FA=$(lsattr "$SYSTEM")
|
||||||
if [[ "$FA" != *"C"* ]]; then
|
if [[ "$FA" != *"C"* ]]; then
|
||||||
error "Failed to disable COW for system image $SYSTEM on ${FS^^} filesystem (returned $FA)"
|
error "Failed to disable COW for system image $SYSTEM on ${FS^^} filesystem."
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ set -Eeuo pipefail
|
|||||||
|
|
||||||
# Docker environment variables
|
# Docker environment variables
|
||||||
|
|
||||||
|
: "${MAC:=""}"
|
||||||
: "${DHCP:="N"}"
|
: "${DHCP:="N"}"
|
||||||
: "${MAC:="02:11:32:AA:BB:CC"}"
|
|
||||||
|
|
||||||
: "${VM_NET_DEV:=""}"
|
: "${VM_NET_DEV:=""}"
|
||||||
: "${VM_NET_TAP:="dsm"}"
|
: "${VM_NET_TAP:="dsm"}"
|
||||||
@@ -33,7 +33,7 @@ configureDHCP() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
while ! ip link set "$VM_NET_TAP" up; do
|
while ! ip link set "$VM_NET_TAP" up; do
|
||||||
info "Waiting for address to become available..."
|
info "Waiting for MAC address $VM_NET_MAC to become available..."
|
||||||
sleep 2
|
sleep 2
|
||||||
done
|
done
|
||||||
|
|
||||||
@@ -80,10 +80,16 @@ configureDNS() {
|
|||||||
|
|
||||||
# Set DNS server and gateway
|
# Set DNS server and gateway
|
||||||
DNSMASQ_OPTS="$DNSMASQ_OPTS --dhcp-option=option:dns-server,${VM_NET_IP%.*}.1 --dhcp-option=option:router,${VM_NET_IP%.*}.1"
|
DNSMASQ_OPTS="$DNSMASQ_OPTS --dhcp-option=option:dns-server,${VM_NET_IP%.*}.1 --dhcp-option=option:router,${VM_NET_IP%.*}.1"
|
||||||
DNSMASQ_OPTS=$(echo "$DNSMASQ_OPTS" | sed 's/\t/ /g' | tr -s ' ' | sed 's/^ *//')
|
|
||||||
|
|
||||||
|
# Add DNS entry for container
|
||||||
|
DNSMASQ_OPTS="$DNSMASQ_OPTS --address=/host.lan/${VM_NET_IP%.*}.1"
|
||||||
|
|
||||||
|
DNSMASQ_OPTS=$(echo "$DNSMASQ_OPTS" | sed 's/\t/ /g' | tr -s ' ' | sed 's/^ *//')
|
||||||
[[ "$DEBUG" == [Yy1]* ]] && set -x
|
[[ "$DEBUG" == [Yy1]* ]] && set -x
|
||||||
$DNSMASQ ${DNSMASQ_OPTS:+ $DNSMASQ_OPTS}
|
|
||||||
|
if ! $DNSMASQ ${DNSMASQ_OPTS:+ $DNSMASQ_OPTS}; then
|
||||||
|
error "Failed to start dnsmasq, reason: $?" && exit 29
|
||||||
|
fi
|
||||||
{ set +x; } 2>/dev/null
|
{ set +x; } 2>/dev/null
|
||||||
[[ "$DEBUG" == [Yy1]* ]] && echo
|
[[ "$DEBUG" == [Yy1]* ]] && echo
|
||||||
|
|
||||||
@@ -115,7 +121,6 @@ configureNAT() {
|
|||||||
# Create a bridge with a static IP for the VM guest
|
# Create a bridge with a static IP for the VM guest
|
||||||
|
|
||||||
VM_NET_IP='20.20.20.21'
|
VM_NET_IP='20.20.20.21'
|
||||||
[[ "$DEBUG" == [Yy1]* ]] && set -x
|
|
||||||
|
|
||||||
{ ip link add dev dockerbridge type bridge ; rc=$?; } || :
|
{ ip link add dev dockerbridge type bridge ; rc=$?; } || :
|
||||||
|
|
||||||
@@ -126,7 +131,7 @@ configureNAT() {
|
|||||||
ip address add ${VM_NET_IP%.*}.1/24 broadcast ${VM_NET_IP%.*}.255 dev dockerbridge
|
ip address add ${VM_NET_IP%.*}.1/24 broadcast ${VM_NET_IP%.*}.255 dev dockerbridge
|
||||||
|
|
||||||
while ! ip link set dockerbridge up; do
|
while ! ip link set dockerbridge up; do
|
||||||
info "Waiting for address to become available..."
|
info "Waiting for IP address to become available..."
|
||||||
sleep 2
|
sleep 2
|
||||||
done
|
done
|
||||||
|
|
||||||
@@ -134,7 +139,7 @@ configureNAT() {
|
|||||||
ip tuntap add dev "$VM_NET_TAP" mode tap
|
ip tuntap add dev "$VM_NET_TAP" mode tap
|
||||||
|
|
||||||
while ! ip link set "$VM_NET_TAP" up promisc on; do
|
while ! ip link set "$VM_NET_TAP" up promisc on; do
|
||||||
info "Waiting for tap to become available..."
|
info "Waiting for TAP to become available..."
|
||||||
sleep 2
|
sleep 2
|
||||||
done
|
done
|
||||||
|
|
||||||
@@ -153,9 +158,6 @@ configureNAT() {
|
|||||||
iptables -A POSTROUTING -t mangle -p udp --dport bootpc -j CHECKSUM --checksum-fill || true
|
iptables -A POSTROUTING -t mangle -p udp --dport bootpc -j CHECKSUM --checksum-fill || true
|
||||||
fi
|
fi
|
||||||
|
|
||||||
{ set +x; } 2>/dev/null
|
|
||||||
[[ "$DEBUG" == [Yy1]* ]] && echo
|
|
||||||
|
|
||||||
NET_OPTS="-netdev tap,ifname=$VM_NET_TAP,script=no,downscript=no,id=hostnet0"
|
NET_OPTS="-netdev tap,ifname=$VM_NET_TAP,script=no,downscript=no,id=hostnet0"
|
||||||
|
|
||||||
{ exec 40>>/dev/vhost-net; rc=$?; } 2>/dev/null || :
|
{ exec 40>>/dev/vhost-net; rc=$?; } 2>/dev/null || :
|
||||||
@@ -209,14 +211,21 @@ getInfo() {
|
|||||||
error "$ADD_ERR -e \"VM_NET_DEV=NAME\" to specify another interface name." && exit 27
|
error "$ADD_ERR -e \"VM_NET_DEV=NAME\" to specify another interface name." && exit 27
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [ -z "$VM_NET_MAC" ]; then
|
||||||
|
# Generate MAC address based on Docker container ID in hostname
|
||||||
|
VM_NET_MAC=$(echo "$HOST" | md5sum | sed 's/^\(..\)\(..\)\(..\)\(..\)\(..\).*$/02:11:32:\3:\4:\5/')
|
||||||
|
fi
|
||||||
|
|
||||||
|
VM_NET_MAC="${VM_NET_MAC^^}"
|
||||||
VM_NET_MAC="${VM_NET_MAC//-/:}"
|
VM_NET_MAC="${VM_NET_MAC//-/:}"
|
||||||
|
|
||||||
if [[ ${#VM_NET_MAC} == 12 ]]; then
|
if [[ ${#VM_NET_MAC} == 12 ]]; then
|
||||||
m="$VM_NET_MAC"
|
m="$VM_NET_MAC"
|
||||||
VM_NET_MAC="${m:0:2}:${m:2:2}:${m:4:2}:${m:6:2}:${m:8:2}:${m:10:2}"
|
VM_NET_MAC="${m:0:2}:${m:2:2}:${m:4:2}:${m:6:2}:${m:8:2}:${m:10:2}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ ${#VM_NET_MAC} != 17 ]]; then
|
if [[ ${#VM_NET_MAC} != 17 ]]; then
|
||||||
error "Invalid mac address: '$VM_NET_MAC', should be 12 or 17 digits long!" && exit 28
|
error "Invalid MAC address: '$VM_NET_MAC', should be 12 or 17 digits long!" && exit 28
|
||||||
fi
|
fi
|
||||||
|
|
||||||
GATEWAY=$(ip r | grep default | awk '{print $3}')
|
GATEWAY=$(ip r | grep default | awk '{print $3}')
|
||||||
@@ -240,22 +249,22 @@ getInfo
|
|||||||
html "Initializing network..."
|
html "Initializing network..."
|
||||||
|
|
||||||
if [[ "$DEBUG" == [Yy1]* ]]; then
|
if [[ "$DEBUG" == [Yy1]* ]]; then
|
||||||
info "Container IP is $IP with gateway $GATEWAY on interface $VM_NET_DEV" && echo
|
info "Host: $HOST IP: $IP Gateway: $GATEWAY Interface: $VM_NET_DEV MAC: $VM_NET_MAC"
|
||||||
|
[ -f /etc/resolv.conf ] && grep '^nameserver*' /etc/resolv.conf
|
||||||
|
echo
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "$DHCP" == [Yy1]* ]]; then
|
if [[ "$DHCP" == [Yy1]* ]]; then
|
||||||
|
|
||||||
if [[ "$GATEWAY" == "172."* ]]; then
|
if [[ "$GATEWAY" == "172."* ]] && [[ "$DEBUG" != [Yy1]* ]]; then
|
||||||
if [[ "$DEBUG" != [Yy1]* ]]; then
|
|
||||||
error "You can only enable DHCP while the container is on a macvlan network!" && exit 26
|
error "You can only enable DHCP while the container is on a macvlan network!" && exit 26
|
||||||
fi
|
fi
|
||||||
fi
|
|
||||||
|
|
||||||
# Configuration for DHCP IP
|
# Configuration for DHCP IP
|
||||||
configureDHCP
|
configureDHCP
|
||||||
|
|
||||||
MSG="Please wait while discovering IP..."
|
MSG="Booting DSM instance..."
|
||||||
html "$MSG" "2000"
|
html "$MSG"
|
||||||
|
|
||||||
else
|
else
|
||||||
|
|
||||||
|
|||||||
@@ -34,6 +34,8 @@ finish() {
|
|||||||
local pid
|
local pid
|
||||||
local reason=$1
|
local reason=$1
|
||||||
|
|
||||||
|
touch "$QEMU_END"
|
||||||
|
|
||||||
if [ -f "$QEMU_PID" ]; then
|
if [ -f "$QEMU_PID" ]; then
|
||||||
|
|
||||||
pid=$(<"$QEMU_PID")
|
pid=$(<"$QEMU_PID")
|
||||||
@@ -98,7 +100,6 @@ terminal() {
|
|||||||
|
|
||||||
_graceful_shutdown() {
|
_graceful_shutdown() {
|
||||||
|
|
||||||
local cnt=0
|
|
||||||
local code=$?
|
local code=$?
|
||||||
local pid url response
|
local pid url response
|
||||||
|
|
||||||
@@ -144,6 +145,8 @@ _graceful_shutdown() {
|
|||||||
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
local cnt=0
|
||||||
|
|
||||||
while [ "$cnt" -lt "$QEMU_TIMEOUT" ]; do
|
while [ "$cnt" -lt "$QEMU_TIMEOUT" ]; do
|
||||||
|
|
||||||
! isAlive "$pid" && break
|
! isAlive "$pid" && break
|
||||||
@@ -167,6 +170,7 @@ _graceful_shutdown() {
|
|||||||
|
|
||||||
MON_OPTS="\
|
MON_OPTS="\
|
||||||
-pidfile $QEMU_PID \
|
-pidfile $QEMU_PID \
|
||||||
|
-name $PROCESS,process=$PROCESS,debug-threads=on \
|
||||||
-monitor telnet:localhost:$QEMU_PORT,server,nowait,nodelay"
|
-monitor telnet:localhost:$QEMU_PORT,server,nowait,nodelay"
|
||||||
|
|
||||||
if [[ "$CONSOLE" != [Yy]* ]]; then
|
if [[ "$CONSOLE" != [Yy]* ]]; then
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ info () { printf "%b%s%b" "\E[1;34m❯ \E[1;36m" "$1" "\E[0m\n" >&2; }
|
|||||||
error () { printf "%b%s%b" "\E[1;31m❯ " "ERROR: $1" "\E[0m\n" >&2; }
|
error () { printf "%b%s%b" "\E[1;31m❯ " "ERROR: $1" "\E[0m\n" >&2; }
|
||||||
|
|
||||||
file="/run/shm/dsm.url"
|
file="/run/shm/dsm.url"
|
||||||
|
info="/run/shm/msg.html"
|
||||||
page="/run/shm/index.html"
|
page="/run/shm/index.html"
|
||||||
address="/run/shm/qemu.ip"
|
address="/run/shm/qemu.ip"
|
||||||
shutdown="/run/shm/qemu.end"
|
shutdown="/run/shm/qemu.end"
|
||||||
@@ -80,6 +81,7 @@ if [[ "$location" != "20.20"* ]]; then
|
|||||||
HTML="${HTML/\[5\]/}"
|
HTML="${HTML/\[5\]/}"
|
||||||
|
|
||||||
echo "$HTML" > "$page"
|
echo "$HTML" > "$page"
|
||||||
|
echo "$body" > "$info"
|
||||||
|
|
||||||
else
|
else
|
||||||
|
|
||||||
|
|||||||
49
src/proc.sh
49
src/proc.sh
@@ -5,8 +5,9 @@ set -Eeuo pipefail
|
|||||||
|
|
||||||
: "${KVM:="Y"}"
|
: "${KVM:="Y"}"
|
||||||
: "${HOST_CPU:=""}"
|
: "${HOST_CPU:=""}"
|
||||||
: "${CPU_MODEL:="host"}"
|
: "${CPU_FLAGS:=""}"
|
||||||
: "${CPU_FEATURES:="+ssse3,+sse4.1,+sse4.2"}"
|
: "${CPU_MODEL:=""}"
|
||||||
|
: "${DEF_MODEL:="qemu64"}"
|
||||||
|
|
||||||
[ "$ARCH" != "amd64" ] && KVM="N"
|
[ "$ARCH" != "amd64" ] && KVM="N"
|
||||||
|
|
||||||
@@ -28,7 +29,7 @@ if [[ "$KVM" != [Nn]* ]]; then
|
|||||||
|
|
||||||
if [ -n "$KVM_ERR" ]; then
|
if [ -n "$KVM_ERR" ]; then
|
||||||
KVM="N"
|
KVM="N"
|
||||||
error "KVM acceleration not detected $KVM_ERR, this will cause a major loss of performance."
|
error "KVM acceleration not available $KVM_ERR, this will cause a major loss of performance."
|
||||||
error "See the FAQ on how to enable it, or continue without KVM by setting KVM=N (not recommended)."
|
error "See the FAQ on how to enable it, or continue without KVM by setting KVM=N (not recommended)."
|
||||||
[[ "$DEBUG" != [Yy1]* ]] && exit 88
|
[[ "$DEBUG" != [Yy1]* ]] && exit 88
|
||||||
fi
|
fi
|
||||||
@@ -37,26 +38,54 @@ fi
|
|||||||
|
|
||||||
if [[ "$KVM" != [Nn]* ]]; then
|
if [[ "$KVM" != [Nn]* ]]; then
|
||||||
|
|
||||||
KVM_OPTS=",accel=kvm -enable-kvm"
|
CPU_FEATURES="kvm=on,l3-cache=on"
|
||||||
|
KVM_OPTS=",accel=kvm -enable-kvm -global kvm-pit.lost_tick_policy=discard"
|
||||||
|
|
||||||
if ! grep -qE '^flags.* (sse4_2)' /proc/cpuinfo; then
|
if ! grep -qE '^flags.* (sse4_2)' /proc/cpuinfo; then
|
||||||
error "Your host CPU does not have the SSE4.2 instruction set that Virtual DSM requires to boot."
|
info "Your CPU does not have the SSE4 instruction set that Virtual DSM requires, it will be emulated..."
|
||||||
error "Disable KVM by setting KVM=N to emulate a compatible CPU, at the cost of performance."
|
[ -z "$CPU_MODEL" ] && CPU_MODEL="$DEF_MODEL"
|
||||||
[[ "$DEBUG" != [Yy1]* ]] && exit 89
|
CPU_FEATURES="$CPU_FEATURES,+ssse3,+sse4.1,+sse4.2"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$CPU_MODEL" ]; then
|
||||||
|
CPU_MODEL="host"
|
||||||
|
CPU_FEATURES="$CPU_FEATURES,migratable=no"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
else
|
else
|
||||||
|
|
||||||
KVM_OPTS=""
|
KVM_OPTS=""
|
||||||
|
CPU_FEATURES="l3-cache=on"
|
||||||
|
|
||||||
if [[ "$CPU_MODEL" == "host"* ]]; then
|
|
||||||
if [[ "$ARCH" == "amd64" ]]; then
|
if [[ "$ARCH" == "amd64" ]]; then
|
||||||
CPU_MODEL="max,$CPU_FEATURES"
|
KVM_OPTS=" -accel tcg,thread=multi"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$CPU_MODEL" ]; then
|
||||||
|
if [[ "$ARCH" == "amd64" ]]; then
|
||||||
|
CPU_MODEL="max"
|
||||||
|
CPU_FEATURES="$CPU_FEATURES,migratable=no"
|
||||||
else
|
else
|
||||||
CPU_MODEL="qemu64,$CPU_FEATURES"
|
CPU_MODEL="$DEF_MODEL"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
CPU_FEATURES="$CPU_FEATURES,+ssse3,+sse4.1,+sse4.2"
|
||||||
|
|
||||||
|
fi
|
||||||
|
|
||||||
|
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
|
fi
|
||||||
|
|
||||||
if [ -z "$HOST_CPU" ]; then
|
if [ -z "$HOST_CPU" ]; then
|
||||||
|
|||||||
32
src/progress.sh
Normal file
32
src/progress.sh
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -Eeuo pipefail
|
||||||
|
|
||||||
|
escape () {
|
||||||
|
local s
|
||||||
|
s=${1//&/\&}
|
||||||
|
s=${s//</\<}
|
||||||
|
s=${s//>/\>}
|
||||||
|
s=${s//'"'/\"}
|
||||||
|
printf -- %s "$s"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
file="$1"
|
||||||
|
body=$(escape "$2")
|
||||||
|
info="/run/shm/msg.html"
|
||||||
|
|
||||||
|
if [[ "$body" == *"..." ]]; then
|
||||||
|
body="<p class=\"loading\">${body/.../}</p>"
|
||||||
|
fi
|
||||||
|
|
||||||
|
while true
|
||||||
|
do
|
||||||
|
if [ -f "$file" ]; then
|
||||||
|
bytes=$(du -sb "$file" | cut -f1)
|
||||||
|
if (( bytes > 1000 )); then
|
||||||
|
size=$(echo "$bytes" | numfmt --to=iec --suffix=B | sed -r 's/([A-Z])/ \1/')
|
||||||
|
echo "${body//(\[P\])/($size)}"> "$info"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
sleep 1 & wait $!
|
||||||
|
done
|
||||||
28
src/reset.sh
28
src/reset.sh
@@ -28,31 +28,36 @@ echo
|
|||||||
|
|
||||||
# Helper variables
|
# Helper variables
|
||||||
|
|
||||||
|
PROCESS="${APP,,}"
|
||||||
|
PROCESS="${PROCESS// /-}"
|
||||||
|
|
||||||
STORAGE="/storage"
|
STORAGE="/storage"
|
||||||
|
INFO="/run/shm/msg.html"
|
||||||
PAGE="/run/shm/index.html"
|
PAGE="/run/shm/index.html"
|
||||||
TEMPLATE="/var/www/index.html"
|
TEMPLATE="/var/www/index.html"
|
||||||
FOOTER1="$APP for Docker v$(</run/version)"
|
FOOTER1="$APP for Docker v$(</run/version)"
|
||||||
FOOTER2="<a href='$SUPPORT'>$SUPPORT</a>"
|
FOOTER2="<a href='$SUPPORT'>$SUPPORT</a>"
|
||||||
|
|
||||||
|
HOST=$(hostname -s)
|
||||||
KERNEL=$(uname -r | cut -b 1)
|
KERNEL=$(uname -r | cut -b 1)
|
||||||
MINOR=$(uname -r | cut -d '.' -f2)
|
MINOR=$(uname -r | cut -d '.' -f2)
|
||||||
ARCH=$(dpkg --print-architecture)
|
ARCH=$(dpkg --print-architecture)
|
||||||
VERS=$(qemu-system-x86_64 --version | head -n 1 | cut -d '(' -f 1)
|
VERS=$(qemu-system-x86_64 --version | head -n 1 | cut -d '(' -f 1)
|
||||||
|
|
||||||
|
# Check system
|
||||||
|
|
||||||
|
if [ ! -d "/dev/shm" ]; then
|
||||||
|
error "Directory /dev/shm not found!" && exit 14
|
||||||
|
else
|
||||||
|
[ ! -d "/run/shm" ] && ln -s /dev/shm /run/shm
|
||||||
|
fi
|
||||||
|
|
||||||
# Check folder
|
# Check folder
|
||||||
|
|
||||||
if [ ! -d "$STORAGE" ]; then
|
if [ ! -d "$STORAGE" ]; then
|
||||||
error "Storage folder ($STORAGE) not found!" && exit 13
|
error "Storage folder ($STORAGE) not found!" && exit 13
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ ! -d "/run/shm" ]; then
|
|
||||||
if [ -d "/dev/shm" ]; then
|
|
||||||
ln -s /dev/shm /run/shm
|
|
||||||
else
|
|
||||||
error "Folder /dev/shm not found!" && exit 14
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Cleanup files
|
# Cleanup files
|
||||||
rm -f /run/shm/qemu.*
|
rm -f /run/shm/qemu.*
|
||||||
rm -f /run/shm/dsm.url
|
rm -f /run/shm/dsm.url
|
||||||
@@ -118,6 +123,7 @@ html()
|
|||||||
{
|
{
|
||||||
local title
|
local title
|
||||||
local body
|
local body
|
||||||
|
local script
|
||||||
local footer
|
local footer
|
||||||
|
|
||||||
title=$(escape "$APP")
|
title=$(escape "$APP")
|
||||||
@@ -129,10 +135,7 @@ html()
|
|||||||
body="<p class=\"loading\">${body/.../}</p>"
|
body="<p class=\"loading\">${body/.../}</p>"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
local timeout="4999"
|
[ -n "${2:-}" ] && script="$2" || script=""
|
||||||
[ -n "${2:-}" ] && timeout="$2"
|
|
||||||
local script="<script>setTimeout(() => { document.location.reload(); }, $timeout);</script>"
|
|
||||||
[[ "$timeout" == "0" ]] && script=""
|
|
||||||
|
|
||||||
local HTML
|
local HTML
|
||||||
HTML=$(<"$TEMPLATE")
|
HTML=$(<"$TEMPLATE")
|
||||||
@@ -143,6 +146,7 @@ html()
|
|||||||
HTML="${HTML/\[5\]/$FOOTER2}"
|
HTML="${HTML/\[5\]/$FOOTER2}"
|
||||||
|
|
||||||
echo "$HTML" > "$PAGE"
|
echo "$HTML" > "$PAGE"
|
||||||
|
echo "$body" > "$INFO"
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,21 @@ set -Eeuo pipefail
|
|||||||
: "${HOST_MODEL:=""}"
|
: "${HOST_MODEL:=""}"
|
||||||
: "${GUEST_SERIAL:=""}"
|
: "${GUEST_SERIAL:=""}"
|
||||||
|
|
||||||
|
if [ -n "$HOST_MAC" ]; then
|
||||||
|
|
||||||
|
HOST_MAC="${HOST_MAC//-/:}"
|
||||||
|
|
||||||
|
if [[ ${#HOST_MAC} == 12 ]]; then
|
||||||
|
m="$HOST_MAC"
|
||||||
|
HOST_MAC="${m:0:2}:${m:2:2}:${m:4:2}:${m:6:2}:${m:8:2}:${m:10:2}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ${#HOST_MAC} != 17 ]]; then
|
||||||
|
error "Invalid HOST_MAC address: '$HOST_MAC', should be 12 or 17 digits long!" && exit 28
|
||||||
|
fi
|
||||||
|
|
||||||
|
fi
|
||||||
|
|
||||||
HOST_ARGS=()
|
HOST_ARGS=()
|
||||||
HOST_ARGS+=("-cpu=$CPU_CORES")
|
HOST_ARGS+=("-cpu=$CPU_CORES")
|
||||||
HOST_ARGS+=("-cpu_arch=$HOST_CPU")
|
HOST_ARGS+=("-cpu_arch=$HOST_CPU")
|
||||||
|
|||||||
167
web/css/style.css
Normal file
167
web/css/style.css
Normal file
@@ -0,0 +1,167 @@
|
|||||||
|
body {
|
||||||
|
color: white;
|
||||||
|
background-color: #125bdb;
|
||||||
|
font-smoothing: antialiased;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
font-family: Verdana, Geneva, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
#info {
|
||||||
|
text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.25);
|
||||||
|
}
|
||||||
|
|
||||||
|
#content {
|
||||||
|
text-align: center;
|
||||||
|
padding: 20px;
|
||||||
|
margin-top: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer {
|
||||||
|
width: 98%;
|
||||||
|
position: fixed;
|
||||||
|
bottom: 0px;
|
||||||
|
height: 40px;
|
||||||
|
text-align: center;
|
||||||
|
color: #0c8aeb;
|
||||||
|
text-shadow: 0 0 1px #0c8aeb;
|
||||||
|
}
|
||||||
|
|
||||||
|
#empty {
|
||||||
|
height: 40px;
|
||||||
|
/* Same height as footer */
|
||||||
|
}
|
||||||
|
|
||||||
|
a,
|
||||||
|
a:hover,
|
||||||
|
a:active,
|
||||||
|
a:visited {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer a:link,
|
||||||
|
footer a:visited,
|
||||||
|
footer a:active {
|
||||||
|
color: #0c8aeb;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer a:hover {
|
||||||
|
color: #73e6ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading:after {
|
||||||
|
content: " .";
|
||||||
|
animation: dots 1s steps(5, end) infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes dots {
|
||||||
|
|
||||||
|
0%,
|
||||||
|
20% {
|
||||||
|
color: rgba(0, 0, 0, 0);
|
||||||
|
text-shadow: 0.25em 0 0 rgba(0, 0, 0, 0), 0.5em 0 0 rgba(0, 0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
40% {
|
||||||
|
color: white;
|
||||||
|
text-shadow: 0.25em 0 0 rgba(0, 0, 0, 0), 0.5em 0 0 rgba(0, 0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
60% {
|
||||||
|
text-shadow: 0.25em 0 0 white, 0.5em 0 0 rgba(0, 0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
80%,
|
||||||
|
100% {
|
||||||
|
text-shadow: 0.25em 0 0 white, 0.5em 0 0 white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.spinner_LWk7 {
|
||||||
|
animation: spinner_GWy6 1.2s linear infinite, spinner_BNNO 1.2s linear infinite
|
||||||
|
}
|
||||||
|
|
||||||
|
.spinner_yOMU {
|
||||||
|
animation: spinner_GWy6 1.2s linear infinite, spinner_pVqn 1.2s linear infinite;
|
||||||
|
animation-delay: .15s
|
||||||
|
}
|
||||||
|
|
||||||
|
.spinner_KS4S {
|
||||||
|
animation: spinner_GWy6 1.2s linear infinite, spinner_6uKB 1.2s linear infinite;
|
||||||
|
animation-delay: .3s
|
||||||
|
}
|
||||||
|
|
||||||
|
.spinner_zVee {
|
||||||
|
animation: spinner_GWy6 1.2s linear infinite, spinner_Qw4x 1.2s linear infinite;
|
||||||
|
animation-delay: .45s
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes spinner_GWy6 {
|
||||||
|
|
||||||
|
0%,
|
||||||
|
50% {
|
||||||
|
width: 9px;
|
||||||
|
height: 9px
|
||||||
|
}
|
||||||
|
|
||||||
|
10% {
|
||||||
|
width: 11px;
|
||||||
|
height: 11px
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes spinner_BNNO {
|
||||||
|
|
||||||
|
0%,
|
||||||
|
50% {
|
||||||
|
x: 1.5px;
|
||||||
|
y: 1.5px
|
||||||
|
}
|
||||||
|
|
||||||
|
10% {
|
||||||
|
x: .5px;
|
||||||
|
y: .5px
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes spinner_pVqn {
|
||||||
|
|
||||||
|
0%,
|
||||||
|
50% {
|
||||||
|
x: 13.5px;
|
||||||
|
y: 1.5px
|
||||||
|
}
|
||||||
|
|
||||||
|
10% {
|
||||||
|
x: 12.5px;
|
||||||
|
y: .5px
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes spinner_6uKB {
|
||||||
|
|
||||||
|
0%,
|
||||||
|
50% {
|
||||||
|
x: 13.5px;
|
||||||
|
y: 13.5px
|
||||||
|
}
|
||||||
|
|
||||||
|
10% {
|
||||||
|
x: 12.5px;
|
||||||
|
y: 12.5px
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes spinner_Qw4x {
|
||||||
|
|
||||||
|
0%,
|
||||||
|
50% {
|
||||||
|
x: 1.5px;
|
||||||
|
y: 13.5px
|
||||||
|
}
|
||||||
|
|
||||||
|
10% {
|
||||||
|
x: .5px;
|
||||||
|
y: 12.5px
|
||||||
|
}
|
||||||
|
}
|
||||||
1
web/img/favicon.svg
Normal file
1
web/img/favicon.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg id="Capa_1" enable-background="new 0 0 511.962 511.962" height="512" viewBox="0 0 511.962 511.962" width="512" xmlns="http://www.w3.org/2000/svg"><g><path d="m489.965 120.063c0-5.77-3.31-11.028-8.512-13.524l-218.984-105.063c-4.102-1.967-8.875-1.967-12.977 0l-218.985 105.063c-5.202 2.496-8.511 7.755-8.511 13.524l-.003 271.834c0 5.77 3.31 11.028 8.512 13.524l218.989 105.064c2.051.983 4.27 1.476 6.488 1.476 2.219 0 4.438-.492 6.488-1.476l218.989-105.064c5.202-2.496 8.512-7.755 8.512-13.524z" fill="#4e6ba6"/><path d="m489.965 120.063c0-5.77-3.31-11.028-8.512-13.524l-218.984-105.063c-2.051-.984-4.269-1.476-6.488-1.476v511.962c2.219 0 4.438-.492 6.488-1.476l218.989-105.064c5.202-2.496 8.512-7.755 8.512-13.524z" fill="#28487a"/><path d="m425.812 160.441c0-2.27-.519-4.457-1.457-6.432l-336.701-.095c-.967 1.999-1.504 4.22-1.504 6.526l-.002 191.081c0 5.769 3.31 11.028 8.512 13.524l154.833 74.285c2.051.983 4.27 1.476 6.488 1.476 2.219 0 4.438-.492 6.488-1.476l154.834-74.285c5.202-2.496 8.512-7.755 8.512-13.524z" fill="#8dc2eb"/><path d="m424.354 154.009h-168.373v286.798c2.219 0 4.438-.492 6.488-1.476l154.834-74.285c5.202-2.496 8.512-7.755 8.512-13.524l-.003-191.081c0-2.27-.52-4.458-1.458-6.432z" fill="#5e9ff6"/><path d="m417.3 146.916-154.831-74.284c-4.102-1.967-8.875-1.967-12.977 0l-154.831 74.284c-3.122 1.498-5.555 3.996-7.007 6.998l168.328 80.812 168.374-80.717c-1.448-3.044-3.9-5.579-7.056-7.093z" fill="#ecf9fd"/><path d="m417.3 146.916-154.831-74.284c-2.051-.983-4.27-1.476-6.488-1.476v163.569l168.374-80.717c-1.447-3.043-3.899-5.578-7.055-7.092z" fill="#d9f3fc"/></g></svg>
|
||||||
|
After Width: | Height: | Size: 1.6 KiB |
@@ -5,22 +5,30 @@
|
|||||||
[1]
|
[1]
|
||||||
<meta http-equiv="Cache-Control" content="no-cache" />
|
<meta http-equiv="Cache-Control" content="no-cache" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<link rel="stylesheet" type="text/css" href="style.css" />
|
<link rel="stylesheet" type="text/css" href="/css/style.css" />
|
||||||
|
<link rel="icon" href="/img/favicon.svg" type="image/x-icon">
|
||||||
[2]
|
[2]
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div id="page-container">
|
<div id="page">
|
||||||
<div id="content-wrap">
|
<div id="content">
|
||||||
<h1>[3]</h1>
|
<svg id="spinner" width="64" height="64" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<rect class="spinner_LWk7" fill="#0c8aeb" x="1.5" y="1.5" rx="1" width="9" height="9"/>
|
||||||
|
<rect class="spinner_yOMU" fill="#0c8aeb" x="13.5" y="1.5" rx="1" width="9" height="9"/>
|
||||||
|
<rect class="spinner_KS4S" fill="#0c8aeb" x="13.5" y="13.5" rx="1" width="9" height="9"/>
|
||||||
|
<rect class="spinner_zVee" fill="#0c8aeb" x="1.5" y="13.5" rx="1" width="9" height="9"/>
|
||||||
|
</svg>
|
||||||
|
<h1 id="info">[3]</h1>
|
||||||
</div>
|
</div>
|
||||||
<div id="empty-space">
|
<div id="empty">
|
||||||
</div>
|
</div>
|
||||||
<div id="footer">
|
<footer id="footer">
|
||||||
[4]<br />
|
[4]<br />
|
||||||
[5]
|
[5]
|
||||||
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<script type="text/javascript" src="/js/script.js"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
130
web/js/script.js
Normal file
130
web/js/script.js
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
var request;
|
||||||
|
var interval = 1000;
|
||||||
|
|
||||||
|
function getInfo() {
|
||||||
|
|
||||||
|
var url = "/msg.html";
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
if (window.XMLHttpRequest) {
|
||||||
|
request = new XMLHttpRequest();
|
||||||
|
} else {
|
||||||
|
throw "XMLHttpRequest not available!";
|
||||||
|
}
|
||||||
|
|
||||||
|
request.onreadystatechange = processInfo;
|
||||||
|
request.open("GET", url, true);
|
||||||
|
request.send();
|
||||||
|
|
||||||
|
} catch (e) {
|
||||||
|
var err = "Error: " + e.message;
|
||||||
|
console.log(err);
|
||||||
|
setError(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function processInfo() {
|
||||||
|
try {
|
||||||
|
if (request.readyState != 4) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
var msg = request.responseText;
|
||||||
|
if (msg == null || msg.length == 0) {
|
||||||
|
setInfo("Booting DSM instance", true);
|
||||||
|
schedule();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var notFound = (request.status == 404);
|
||||||
|
|
||||||
|
if (request.status == 200) {
|
||||||
|
if (msg.toLowerCase().indexOf("<html>") !== -1) {
|
||||||
|
notFound = true;
|
||||||
|
} else {
|
||||||
|
if (msg.toLowerCase().indexOf("href=") !== -1) {
|
||||||
|
var div = document.createElement("div");
|
||||||
|
div.innerHTML = msg;
|
||||||
|
var url = div.querySelector("a").href;
|
||||||
|
setTimeout(() => {
|
||||||
|
window.location.assign(url);
|
||||||
|
}, 3000);
|
||||||
|
setInfo(msg);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
setInfo(msg);
|
||||||
|
schedule();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (notFound) {
|
||||||
|
setInfo("Connecting to web portal", true);
|
||||||
|
reload();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
setError("Error: Received statuscode " + request.status);
|
||||||
|
schedule();
|
||||||
|
return false;
|
||||||
|
|
||||||
|
} catch (e) {
|
||||||
|
var err = "Error: " + e.message;
|
||||||
|
console.log(err);
|
||||||
|
setError(err);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setInfo(msg, loading, error) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (msg == null || msg.length == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var el = document.getElementById("spinner");
|
||||||
|
|
||||||
|
error = !!error;
|
||||||
|
if (!error) {
|
||||||
|
el.style.visibility = 'visible';
|
||||||
|
} else {
|
||||||
|
el.style.visibility = 'hidden';
|
||||||
|
}
|
||||||
|
|
||||||
|
loading = !!loading;
|
||||||
|
if (loading) {
|
||||||
|
msg = "<p class=\"loading\">" + msg + "</p>";
|
||||||
|
}
|
||||||
|
|
||||||
|
el = document.getElementById("info");
|
||||||
|
|
||||||
|
if (el.innerHTML != msg) {
|
||||||
|
el.innerHTML = msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
} catch (e) {
|
||||||
|
console.log("Error: " + e.message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setError(text) {
|
||||||
|
return setInfo(text, false, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function schedule() {
|
||||||
|
setTimeout(getInfo, interval);
|
||||||
|
}
|
||||||
|
|
||||||
|
function reload() {
|
||||||
|
setTimeout(() => {
|
||||||
|
document.location.reload();
|
||||||
|
}, 3000);
|
||||||
|
}
|
||||||
|
|
||||||
|
schedule();
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
body {
|
|
||||||
color: white;
|
|
||||||
background-color: #125bdb;
|
|
||||||
font-family: Verdana, Arial, sans-serif;
|
|
||||||
}
|
|
||||||
|
|
||||||
#content-wrap {
|
|
||||||
text-align: center;
|
|
||||||
padding: 20px;
|
|
||||||
margin-top: 100px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#footer {
|
|
||||||
width: 98%;
|
|
||||||
position: fixed;
|
|
||||||
bottom: 0px;
|
|
||||||
height: 40px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
#empty-space {
|
|
||||||
height: 40px;
|
|
||||||
/* Same height as footer */
|
|
||||||
}
|
|
||||||
|
|
||||||
a,
|
|
||||||
a:hover,
|
|
||||||
a:active,
|
|
||||||
a:visited {
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.loading:after {
|
|
||||||
content: " .";
|
|
||||||
animation: dots 1s steps(5, end) infinite;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes dots {
|
|
||||||
|
|
||||||
0%,
|
|
||||||
20% {
|
|
||||||
color: rgba(0, 0, 0, 0);
|
|
||||||
text-shadow: 0.25em 0 0 rgba(0, 0, 0, 0), 0.5em 0 0 rgba(0, 0, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
40% {
|
|
||||||
color: white;
|
|
||||||
text-shadow: 0.25em 0 0 rgba(0, 0, 0, 0), 0.5em 0 0 rgba(0, 0, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
60% {
|
|
||||||
text-shadow: 0.25em 0 0 white, 0.5em 0 0 rgba(0, 0, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
80%,
|
|
||||||
100% {
|
|
||||||
text-shadow: 0.25em 0 0 white, 0.5em 0 0 white;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user