Initial commit
Initial commit
This commit is contained in:
commit
50a89476c3
17 changed files with 47 additions and 737 deletions
41
Dockerfile
41
Dockerfile
|
@ -1,27 +1,11 @@
|
||||||
FROM golang:1.20 AS builder
|
|
||||||
|
|
||||||
COPY serial/ /src/serial/
|
|
||||||
WORKDIR /src/serial
|
|
||||||
|
|
||||||
RUN go get -d -v golang.org/x/net/html
|
|
||||||
RUN go get -d -v github.com/gorilla/mux
|
|
||||||
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o /src/serial/main .
|
|
||||||
|
|
||||||
FROM debian:bookworm-20230320-slim
|
FROM debian:bookworm-20230320-slim
|
||||||
|
|
||||||
RUN apt-get update && apt-get -y upgrade && \
|
RUN apt-get update && apt-get -y upgrade && \
|
||||||
apt-get --no-install-recommends -y install \
|
apt-get --no-install-recommends -y install \
|
||||||
jq \
|
|
||||||
curl \
|
|
||||||
cpio \
|
|
||||||
wget \
|
wget \
|
||||||
unzip \
|
|
||||||
procps \
|
|
||||||
dnsmasq \
|
dnsmasq \
|
||||||
iptables \
|
iptables \
|
||||||
iproute2 \
|
iproute2 \
|
||||||
xz-utils \
|
|
||||||
btrfs-progs \
|
|
||||||
bridge-utils \
|
bridge-utils \
|
||||||
netcat-openbsd \
|
netcat-openbsd \
|
||||||
ca-certificates \
|
ca-certificates \
|
||||||
|
@ -31,43 +15,20 @@ RUN apt-get update && apt-get -y upgrade && \
|
||||||
COPY run.sh /run/
|
COPY run.sh /run/
|
||||||
COPY disk.sh /run/
|
COPY disk.sh /run/
|
||||||
COPY power.sh /run/
|
COPY power.sh /run/
|
||||||
COPY serial.sh /run/
|
|
||||||
COPY server.sh /run/
|
|
||||||
COPY install.sh /run/
|
COPY install.sh /run/
|
||||||
COPY network.sh /run/
|
COPY network.sh /run/
|
||||||
|
|
||||||
COPY agent/agent.sh /agent/
|
|
||||||
COPY agent/service.sh /agent/
|
|
||||||
|
|
||||||
COPY --from=builder /src/serial/main /run/serial.bin
|
|
||||||
|
|
||||||
RUN ["chmod", "+x", "/run/run.sh"]
|
RUN ["chmod", "+x", "/run/run.sh"]
|
||||||
RUN ["chmod", "+x", "/run/disk.sh"]
|
|
||||||
RUN ["chmod", "+x", "/run/power.sh"]
|
|
||||||
RUN ["chmod", "+x", "/run/serial.sh"]
|
|
||||||
RUN ["chmod", "+x", "/run/server.sh"]
|
|
||||||
RUN ["chmod", "+x", "/run/install.sh"]
|
RUN ["chmod", "+x", "/run/install.sh"]
|
||||||
RUN ["chmod", "+x", "/run/network.sh"]
|
|
||||||
RUN ["chmod", "+x", "/run/serial.bin"]
|
|
||||||
|
|
||||||
COPY disks/template.img.xz /data/
|
|
||||||
|
|
||||||
VOLUME /storage
|
VOLUME /storage
|
||||||
|
|
||||||
EXPOSE 22
|
EXPOSE 22
|
||||||
EXPOSE 80
|
|
||||||
EXPOSE 139
|
|
||||||
EXPOSE 443
|
|
||||||
EXPOSE 445
|
|
||||||
EXPOSE 5000
|
|
||||||
EXPOSE 5001
|
|
||||||
|
|
||||||
ENV CPU_CORES 1
|
ENV CPU_CORES 1
|
||||||
ENV DISK_SIZE 16G
|
ENV DISK_SIZE 16G
|
||||||
ENV RAM_SIZE 512M
|
ENV RAM_SIZE 512M
|
||||||
|
|
||||||
#ENV URL https://global.synologydownload.com/download/DSM/beta/7.2/64216/DSM_VirtualDSM_64216.pat
|
ENV BOOT https://ftp.halifax.rwth-aachen.de/osdn/clonezilla/78259/clonezilla-live-3.0.3-22-amd64.iso
|
||||||
#ENV URL https://global.synologydownload.com/download/DSM/release/7.0.1/42218/DSM_VirtualDSM_42218.pat
|
|
||||||
ENV URL https://global.synologydownload.com/download/DSM/release/7.1.1/42962-1/DSM_VirtualDSM_42962.pat
|
|
||||||
|
|
||||||
ENTRYPOINT ["/run/run.sh"]
|
ENTRYPOINT ["/run/run.sh"]
|
||||||
|
|
|
@ -1,65 +0,0 @@
|
||||||
#!/usr/bin/env bash
|
|
||||||
set -u
|
|
||||||
|
|
||||||
declare nmi
|
|
||||||
|
|
||||||
function checkNMI {
|
|
||||||
|
|
||||||
nmi=$(cat /proc/interrupts | grep NMI)
|
|
||||||
nmi=$(echo "$nmi" | sed 's/[^0-9]*//g')
|
|
||||||
nmi=$(echo "$nmi" | sed 's/^0*//')
|
|
||||||
|
|
||||||
if [ "$nmi" != "" ]; then
|
|
||||||
|
|
||||||
echo "Received shutdown request through NMI.." > /dev/ttyS0
|
|
||||||
|
|
||||||
/usr/syno/sbin/synoshutdown -s > /dev/null
|
|
||||||
exit 0
|
|
||||||
|
|
||||||
fi
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
chmod 666 /dev/ttyS0
|
|
||||||
checkNMI
|
|
||||||
|
|
||||||
first_run=false
|
|
||||||
|
|
||||||
for filename in /usr/local/packages/*.spk; do
|
|
||||||
if [ -f "$filename" ]; then
|
|
||||||
first_run=true
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
if [ "$first_run" = true ]; then
|
|
||||||
for filename in /usr/local/packages/*.spk; do
|
|
||||||
if [ -f "$filename" ]; then
|
|
||||||
|
|
||||||
/usr/syno/bin/synopkg install "$filename" > /dev/null
|
|
||||||
|
|
||||||
BASE=$(basename "$filename" .spk)
|
|
||||||
BASE="${BASE%%-*}"
|
|
||||||
|
|
||||||
/usr/syno/bin/synopkg start "$BASE" > /dev/null
|
|
||||||
|
|
||||||
rm "$filename"
|
|
||||||
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
else
|
|
||||||
|
|
||||||
sleep 5
|
|
||||||
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "-------------------------------------------" > /dev/ttyS0
|
|
||||||
echo " You can now login to DSM at port 5000 " > /dev/ttyS0
|
|
||||||
echo "-------------------------------------------" > /dev/ttyS0
|
|
||||||
|
|
||||||
while true; do
|
|
||||||
|
|
||||||
checkNMI
|
|
||||||
sleep 1
|
|
||||||
|
|
||||||
done
|
|
||||||
|
|
|
@ -1,49 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
PIDFILE="/var/run/agent.pid"
|
|
||||||
LOGFILE="/var/log/agent.log"
|
|
||||||
SCRIPT="/usr/local/bin/agent.sh"
|
|
||||||
|
|
||||||
status() {
|
|
||||||
if [ -f "$PIDFILE" ]; then
|
|
||||||
echo 'Service running' >&2
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
start() {
|
|
||||||
if [ -f "$PIDFILE" ] && kill -0 "$(cat "$PIDFILE")"; then
|
|
||||||
echo 'Service already running' >&2
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
printf 'Starting agent service...' >&2
|
|
||||||
"$SCRIPT" &> "$LOGFILE" & echo $! > "$PIDFILE"
|
|
||||||
}
|
|
||||||
|
|
||||||
stop() {
|
|
||||||
if [ ! -f "$PIDFILE" ] || ! kill -0 "$(cat "$PIDFILE")"; then
|
|
||||||
echo 'Service not running' >&2
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
echo 'Stopping agent service' >&2
|
|
||||||
kill -15 "$(cat "$PIDFILE")" && rm -f "$PIDFILE"
|
|
||||||
echo 'Service stopped' >&2
|
|
||||||
}
|
|
||||||
|
|
||||||
case "$1" in
|
|
||||||
start)
|
|
||||||
start
|
|
||||||
;;
|
|
||||||
stop)
|
|
||||||
stop
|
|
||||||
;;
|
|
||||||
status)
|
|
||||||
status
|
|
||||||
;;
|
|
||||||
restart)
|
|
||||||
stop
|
|
||||||
start
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
echo "Usage: $0 {start|stop|restart}"
|
|
||||||
esac
|
|
6
build.sh
6
build.sh
|
@ -1,6 +1,6 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
docker build --tag dsm .
|
docker build --tag qemu .
|
||||||
docker images dsm:latest --format "{{.Repository}}:{{.Tag}} -> {{.Size}}"
|
docker images qemu:latest --format "{{.Repository}}:{{.Tag}} -> {{.Size}}"
|
||||||
docker run --rm -it --name dsm --device="/dev/kvm" --cap-add NET_ADMIN -p 80:5000 -p 443:5001 -p 5000:5000 -p 5001:5001 docker.io/library/dsm
|
docker run --rm -it --name qemu --device="/dev/kvm" --cap-add NET_ADMIN -p 80:80 docker.io/library/qemu
|
||||||
|
|
51
disk.sh
51
disk.sh
|
@ -2,50 +2,21 @@
|
||||||
set -eu
|
set -eu
|
||||||
|
|
||||||
IMG="/storage"
|
IMG="/storage"
|
||||||
BASE=$(basename "$URL" .pat)
|
FILE="$IMG/boot.img"
|
||||||
|
[ ! -f "$FILE" ] && echo "ERROR: Boot image does not exist ($FILE)" && exit 81
|
||||||
FILE="$IMG/$BASE.boot.img"
|
|
||||||
[ ! -f "$FILE" ] && echo "ERROR: Virtual DSM boot-image does not exist ($FILE)" && exit 81
|
|
||||||
|
|
||||||
FILE="$IMG/$BASE.system.img"
|
|
||||||
[ ! -f "$FILE" ] && echo "ERROR: Virtual DSM system-image does not exist ($FILE)" && exit 82
|
|
||||||
|
|
||||||
DISK_SIZE=$(echo "${DISK_SIZE}" | sed 's/MB/M/g;s/GB/G/g;s/TB/T/g')
|
DISK_SIZE=$(echo "${DISK_SIZE}" | sed 's/MB/M/g;s/GB/G/g;s/TB/T/g')
|
||||||
NEW_SIZE=$(numfmt --from=iec "${DISK_SIZE}")
|
NEW_SIZE=$(numfmt --from=iec "${DISK_SIZE}")
|
||||||
|
|
||||||
FILE="$IMG/data$DISK_SIZE.img"
|
FILE="$IMG/data${DISK_SIZE}.img"
|
||||||
|
[ ! -f "$FILE" ] && truncate -s "${NEW_SIZE}" "${FILE}"
|
||||||
if [ ! -f "$FILE" ]; then
|
[ ! -f "$FILE" ] && echo "ERROR: Data image does not exist ($FILE)" && exit 83
|
||||||
truncate -s "${NEW_SIZE}" "${FILE}"
|
|
||||||
mkfs.btrfs -q -L data -d single -m single "${FILE}" > /dev/null
|
|
||||||
#qemu-img convert -f raw -O qcow2 -o extended_l2=on,cluster_size=128k,compression_type=zstd,preallocation=metadata "$TMP" "$FILE"
|
|
||||||
fi
|
|
||||||
|
|
||||||
[ ! -f "$FILE" ] && echo "ERROR: Virtual DSM data-image does not exist ($FILE)" && exit 83
|
|
||||||
|
|
||||||
#OLD_SIZE=$(stat -c%s "${FILE}")
|
|
||||||
#
|
|
||||||
#if [ "$NEW_SIZE" -ne "$OLD_SIZE" ]; then
|
|
||||||
# echo "Resizing data disk from $OLD_SIZE to $NEW_SIZE bytes"
|
|
||||||
#
|
|
||||||
# if [ "$NEW_SIZE" -gt "$OLD_SIZE" ]; then
|
|
||||||
# truncate -s "${NEW_SIZE}" "${FILE}"
|
|
||||||
# btrfs filesystem resize "${NEW_SIZE}" "${FILE}"
|
|
||||||
# fi
|
|
||||||
#
|
|
||||||
# if [ "$NEW_SIZE" -lt "$OLD_SIZE" ]; then
|
|
||||||
# btrfs filesystem resize "${NEW_SIZE}" "${FILE}"
|
|
||||||
# truncate -s "${NEW_SIZE}" "${FILE}"
|
|
||||||
# fi
|
|
||||||
#fi
|
|
||||||
|
|
||||||
KVM_DISK_OPTS="\
|
KVM_DISK_OPTS="\
|
||||||
-device virtio-scsi-pci,id=hw-synoboot,bus=pcie.0,addr=0xa \
|
-device virtio-scsi-pci,id=hw-boot,bus=pcie.0,addr=0xa \
|
||||||
-drive file=${IMG}/${BASE}.boot.img,if=none,id=drive-synoboot,format=raw,cache=none,aio=native,discard=on,detect-zeroes=on \
|
-drive file=${IMG}/boot.img,if=none,id=drive-boot,format=raw,cache=none,aio=native,discard=on,detect-zeroes=on \
|
||||||
-device scsi-hd,bus=hw-synoboot.0,channel=0,scsi-id=0,lun=0,drive=drive-synoboot,id=synoboot0,rotation_rate=1,bootindex=1 \
|
-device scsi-hd,bus=hw-boot.0,channel=0,scsi-id=0,lun=0,drive=drive-boot,id=boot0,rotation_rate=1,bootindex=1 \
|
||||||
-device virtio-scsi-pci,id=hw-synosys,bus=pcie.0,addr=0xb \
|
-device virtio-scsi-pci,id=hw-userdata,bus=pcie.0,addr=0xb \
|
||||||
-drive file=${IMG}/${BASE}.system.img,if=none,id=drive-synosys,format=raw,cache=none,aio=native,discard=on,detect-zeroes=on \
|
|
||||||
-device scsi-hd,bus=hw-synosys.0,channel=0,scsi-id=0,lun=0,drive=drive-synosys,id=synosys0,rotation_rate=1,bootindex=2 \
|
|
||||||
-device virtio-scsi-pci,id=hw-userdata,bus=pcie.0,addr=0xc \
|
|
||||||
-drive file=${IMG}/data${DISK_SIZE}.img,if=none,id=drive-userdata,format=raw,cache=none,aio=native,discard=on,detect-zeroes=on \
|
-drive file=${IMG}/data${DISK_SIZE}.img,if=none,id=drive-userdata,format=raw,cache=none,aio=native,discard=on,detect-zeroes=on \
|
||||||
-device scsi-hd,bus=hw-userdata.0,channel=0,scsi-id=0,lun=0,drive=drive-userdata,id=userdata0,rotation_rate=1,bootindex=3"
|
-device scsi-hd,bus=hw-userdata.0,channel=0,scsi-id=0,lun=0,drive=drive-userdata,id=userdata0,rotation_rate=1,bootindex=2"
|
||||||
|
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
version: "3"
|
version: "3"
|
||||||
services:
|
services:
|
||||||
vm:
|
vm:
|
||||||
container_name: dsm
|
container_name: qemu
|
||||||
image: kroese/virtual-dsm:latest
|
image: kroese/docker-qemu:latest
|
||||||
environment:
|
environment:
|
||||||
CPU_CORES: "1"
|
CPU_CORES: "1"
|
||||||
RAM_SIZE: "512M"
|
RAM_SIZE: "512M"
|
||||||
DISK_SIZE: "16G"
|
DISK_SIZE: "16G"
|
||||||
|
BOOT: "https://ftp.halifax.rwth-aachen.de/osdn/clonezilla/78259/clonezilla-live-3.0.3-22-amd64.iso"
|
||||||
devices:
|
devices:
|
||||||
- /dev/kvm
|
- /dev/kvm
|
||||||
cap_add:
|
cap_add:
|
||||||
- NET_ADMIN
|
- NET_ADMIN
|
||||||
ports:
|
ports:
|
||||||
- 5000:5000
|
- 22:22
|
||||||
- 5001:5001
|
|
||||||
restart: on-failure
|
restart: on-failure
|
||||||
stop_grace_period: 60s
|
stop_grace_period: 60s
|
||||||
|
|
135
install.sh
135
install.sh
|
@ -2,43 +2,14 @@
|
||||||
set -eu
|
set -eu
|
||||||
|
|
||||||
IMG="/storage"
|
IMG="/storage"
|
||||||
BASE=$(basename "$URL" .pat)
|
|
||||||
|
|
||||||
[ ! -d "$IMG" ] && echo "Storage folder (${IMG}) not found!" && exit 69
|
[ ! -d "$IMG" ] && echo "Storage folder (${IMG}) not found!" && exit 69
|
||||||
[ ! -f "/run/server.sh" ] && echo "Script must run inside Docker container!" && exit 60
|
[ -f "$IMG/boot.img" ] && exit 0
|
||||||
|
|
||||||
[ ! -f "$IMG/$BASE.boot.img" ] && rm -f "$IMG"/"$BASE".system.img
|
|
||||||
[ -f "$IMG/$BASE.system.img" ] && exit 0
|
|
||||||
|
|
||||||
# Display wait message on port 5000
|
|
||||||
/run/server.sh 5000 > /dev/null &
|
|
||||||
|
|
||||||
TMP="$IMG/tmp"
|
TMP="$IMG/tmp"
|
||||||
|
|
||||||
echo "Install: Downloading extractor..."
|
echo "Install: Downloading $BOOT..."
|
||||||
|
|
||||||
rm -rf $TMP && mkdir -p $TMP
|
|
||||||
|
|
||||||
FILE="$TMP/rd.gz"
|
|
||||||
curl -r 64493568-69886247 -s -k -o "$FILE" https://global.synologydownload.com/download/DSM/release/7.0.1/42218/DSM_VirtualDSM_42218.pat
|
|
||||||
|
|
||||||
set +e
|
|
||||||
xz -dc <$TMP/rd.gz >$TMP/rd 2>/dev/null
|
|
||||||
(cd $TMP && cpio -idm <$TMP/rd 2>/dev/null)
|
|
||||||
set -e
|
|
||||||
|
|
||||||
mkdir -p /run/extract
|
|
||||||
for file in $TMP/usr/lib/libcurl.so.4 $TMP/usr/lib/libmbedcrypto.so.5 $TMP/usr/lib/libmbedtls.so.13 $TMP/usr/lib/libmbedx509.so.1 $TMP/usr/lib/libmsgpackc.so.2 $TMP/usr/lib/libsodium.so $TMP/usr/lib/libsynocodesign-ng-virtual-junior-wins.so.7 $TMP/usr/syno/bin/scemd; do
|
|
||||||
cp "$file" /run/extract/
|
|
||||||
done
|
|
||||||
|
|
||||||
mv /run/extract/scemd /run/extract/syno_extract_system_patch
|
|
||||||
chmod +x /run/extract/syno_extract_system_patch
|
|
||||||
|
|
||||||
echo "Install: Downloading $URL..."
|
|
||||||
|
|
||||||
FILE="$TMP/dsm.pat"
|
|
||||||
|
|
||||||
|
FILE="$TMP/boot.img"
|
||||||
rm -rf $TMP && mkdir -p $TMP
|
rm -rf $TMP && mkdir -p $TMP
|
||||||
|
|
||||||
# Check if running with interactive TTY or redirected to docker log
|
# Check if running with interactive TTY or redirected to docker log
|
||||||
|
@ -50,105 +21,7 @@ fi
|
||||||
|
|
||||||
[ ! -f "$FILE" ] && echo "Download failed" && exit 61
|
[ ! -f "$FILE" ] && echo "Download failed" && exit 61
|
||||||
|
|
||||||
SIZE=$(stat -c%s "$FILE")
|
mv -f "$BOOT" "$IMG"/boot.img
|
||||||
|
|
||||||
if ((SIZE<250000000)); then
|
|
||||||
echo "Invalid PAT file: File is an update pack which contains no OS image." && exit 62
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "Install: Extracting downloaded system image..."
|
|
||||||
|
|
||||||
if { tar tf "$FILE"; } >/dev/null 2>&1; then
|
|
||||||
tar xpf $FILE -C $TMP/.
|
|
||||||
else
|
|
||||||
export LD_LIBRARY_PATH="/run/extract"
|
|
||||||
if ! /run/extract/syno_extract_system_patch $FILE $TMP/. ; then
|
|
||||||
echo "Invalid PAT file: File is an update pack which contains no OS image." && exit 63
|
|
||||||
fi
|
|
||||||
export LD_LIBRARY_PATH=""
|
|
||||||
fi
|
|
||||||
|
|
||||||
HDA="$TMP/hda1"
|
|
||||||
IDB="$TMP/indexdb"
|
|
||||||
PKG="$TMP/packages"
|
|
||||||
HDP="$TMP/synohdpack_img"
|
|
||||||
|
|
||||||
[ ! -f "$HDA.tgz" ] && echo "Invalid PAT file: File contains no OS image." && exit 64
|
|
||||||
[ ! -f "$HDP.txz" ] && echo "Invalid PAT file: HD pack not found." && exit 65
|
|
||||||
[ ! -f "$IDB.txz" ] && echo "Invalid PAT file: IndexDB file not found." && exit 66
|
|
||||||
[ ! -d "$PKG" ] && echo "Invalid PAT file: File contains no packages." && exit 68
|
|
||||||
|
|
||||||
BOOT=$(find $TMP -name "*.bin.zip")
|
|
||||||
|
|
||||||
[ ! -f "$BOOT" ] && echo "Invalid PAT file: boot file not found." && exit 67
|
|
||||||
|
|
||||||
BOOT=$(echo "$BOOT" | head -c -5)
|
|
||||||
unzip -q -o "$BOOT".zip -d $TMP
|
|
||||||
|
|
||||||
echo "Install: Extracting prepared disk image..."
|
|
||||||
|
|
||||||
SYSTEM="$TMP/temp.img"
|
|
||||||
PLATE="/data/template.img"
|
|
||||||
|
|
||||||
rm -f $PLATE
|
|
||||||
unxz $PLATE.xz
|
|
||||||
mv -f $PLATE $SYSTEM
|
|
||||||
|
|
||||||
echo "Install: Extracting system partition..."
|
|
||||||
|
|
||||||
PRIVILEGED=false
|
|
||||||
LABEL="1.44.1-42218"
|
|
||||||
OFFSET="1048576" # 2048 * 512
|
|
||||||
NUMBLOCKS="622560" # 2550005760 / 4096
|
|
||||||
|
|
||||||
MOUNT="/mnt/tmp"
|
|
||||||
rm -rf $MOUNT && mkdir -p $MOUNT
|
|
||||||
|
|
||||||
mount -t ext4 -o loop,offset=$OFFSET $SYSTEM $MOUNT 2>/dev/null && PRIVILEGED=true
|
|
||||||
|
|
||||||
rm -rf ${MOUNT:?}/{,.[!.],..?}*
|
|
||||||
|
|
||||||
mv -f $HDA.tgz $HDA.txz
|
|
||||||
|
|
||||||
tar xpfJ $HDP.txz --absolute-names -C $MOUNT/
|
|
||||||
tar xpfJ $HDA.txz --absolute-names -C $MOUNT/
|
|
||||||
tar xpfJ $IDB.txz --absolute-names -C $MOUNT/usr/syno/synoman/indexdb/
|
|
||||||
|
|
||||||
LOC="$MOUNT/usr/local"
|
|
||||||
mkdir -p $LOC
|
|
||||||
mv $PKG/ $LOC/
|
|
||||||
|
|
||||||
LOC="$MOUNT/usr/local/bin"
|
|
||||||
mkdir -p $LOC
|
|
||||||
cp /agent/agent.sh $LOC/agent.sh
|
|
||||||
chmod +x $LOC/agent.sh
|
|
||||||
|
|
||||||
LOC="$MOUNT/usr/local/etc/rc.d"
|
|
||||||
mkdir -p $LOC
|
|
||||||
cp /agent/service.sh $LOC/agent.sh
|
|
||||||
chmod +x $LOC/agent.sh
|
|
||||||
|
|
||||||
# Store agent version
|
|
||||||
echo "2" > "$IMG"/agent.ver
|
|
||||||
|
|
||||||
if [ "$PRIVILEGED" = false ]; then
|
|
||||||
|
|
||||||
echo "Install: Installing system partition..."
|
|
||||||
|
|
||||||
# Workaround for containers that are not privileged to mount loop devices
|
|
||||||
mke2fs -q -t ext4 -b 4096 -d $MOUNT/ -L $LABEL -F -E offset=$OFFSET $SYSTEM $NUMBLOCKS
|
|
||||||
|
|
||||||
else
|
|
||||||
|
|
||||||
umount $MOUNT
|
|
||||||
|
|
||||||
fi
|
|
||||||
|
|
||||||
rm -rf $MOUNT
|
|
||||||
|
|
||||||
mv -f "$BOOT" "$IMG"/"$BASE".boot.img
|
|
||||||
mv -f "$SYSTEM" "$IMG"/"$BASE".system.img
|
|
||||||
|
|
||||||
rm -rf $TMP
|
rm -rf $TMP
|
||||||
|
|
||||||
exit 0
|
|
||||||
|
|
10
network.sh
10
network.sh
|
@ -18,7 +18,7 @@ setupLocalDhcp () {
|
||||||
IP="$2"
|
IP="$2"
|
||||||
MAC="$1"
|
MAC="$1"
|
||||||
CIDR="24"
|
CIDR="24"
|
||||||
HOSTNAME="VirtualDSM"
|
HOSTNAME="QEMU"
|
||||||
# dnsmasq configuration:
|
# dnsmasq configuration:
|
||||||
DNSMASQ_OPTS="$DNSMASQ_OPTS --dhcp-range=$IP,$IP --dhcp-host=$MAC,,$IP,$HOSTNAME,infinite --dhcp-option=option:netmask,255.255.255.0"
|
DNSMASQ_OPTS="$DNSMASQ_OPTS --dhcp-range=$IP,$IP --dhcp-host=$MAC,,$IP,$HOSTNAME,infinite --dhcp-option=option:netmask,255.255.255.0"
|
||||||
# Create lease file for faster resolve
|
# Create lease file for faster resolve
|
||||||
|
@ -61,14 +61,6 @@ if [ ! -c /dev/net/tun ]; then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
[ ! -c /dev/net/tun ] && echo "Error: TUN network interface not available..." && exit 85
|
[ ! -c /dev/net/tun ] && echo "Error: TUN network interface not available..." && exit 85
|
||||||
[ ! -d "$IMG" ] && echo "Storage folder (${IMG}) not found!" && exit 86
|
|
||||||
|
|
||||||
#If environment variabele not set fall back to file
|
|
||||||
if [ -z "$VM_NET_MAC" ]; then
|
|
||||||
FILE="${IMG}/guest.mac"
|
|
||||||
[ ! -f "$FILE" ] && echo "00:11:32:2C:A7:85" > "$FILE"
|
|
||||||
VM_NET_MAC=$(cat "${FILE}")
|
|
||||||
fi
|
|
||||||
|
|
||||||
update-alternatives --set iptables /usr/sbin/iptables-legacy > /dev/null
|
update-alternatives --set iptables /usr/sbin/iptables-legacy > /dev/null
|
||||||
update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy > /dev/null
|
update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy > /dev/null
|
||||||
|
|
25
power.sh
25
power.sh
|
@ -25,29 +25,8 @@ _graceful_shutdown(){
|
||||||
echo "Received $1 signal, shutting down..."
|
echo "Received $1 signal, shutting down..."
|
||||||
echo 0 > "${_QEMU_SHUTDOWN_COUNTER}"
|
echo 0 > "${_QEMU_SHUTDOWN_COUNTER}"
|
||||||
|
|
||||||
# Don't send the powerdown signal because vDSM ignores ACPI signals
|
# Send the shutdown (system_powerdown) command to the QMP monitor
|
||||||
# echo 'system_powerdown' | nc -q 1 -w 1 localhost "${QEMU_MONPORT}">/dev/null
|
echo 'system_powerdown' | nc -q 1 -w 1 localhost "${QEMU_MONPORT}">/dev/null
|
||||||
|
|
||||||
# Send shutdown command to guest agent tools instead via serial port
|
|
||||||
RESPONSE=$(curl -s -m 2 -S http://127.0.0.1:2210/write?command=6 2>&1)
|
|
||||||
|
|
||||||
if [[ ! "${RESPONSE}" =~ "\"success\"" ]] ; then
|
|
||||||
|
|
||||||
echo "Could not send shutdown command to guest, error: $RESPONSE"
|
|
||||||
|
|
||||||
FILE="${IMG}/agent.ver"
|
|
||||||
[ ! -f "$FILE" ] && echo "1" > "$FILE"
|
|
||||||
AGENT_VERSION=$(cat "${FILE}")
|
|
||||||
|
|
||||||
if ((AGENT_VERSION < 2)); then
|
|
||||||
echo "Please update the agent to allow gracefull shutdowns..."
|
|
||||||
pkill -f qemu-system-x86_64
|
|
||||||
else
|
|
||||||
# Send a NMI interrupt which will be detected by the kernel
|
|
||||||
echo 'nmi' | nc -q 1 -w 1 localhost "${QEMU_MONPORT}">/dev/null
|
|
||||||
fi
|
|
||||||
|
|
||||||
fi
|
|
||||||
|
|
||||||
while [ "$(cat ${_QEMU_SHUTDOWN_COUNTER})" -lt "${QEMU_POWERDOWN_TIMEOUT}" ]; do
|
while [ "$(cat ${_QEMU_SHUTDOWN_COUNTER})" -lt "${QEMU_POWERDOWN_TIMEOUT}" ]; do
|
||||||
|
|
||||||
|
|
43
readme.md
43
readme.md
|
@ -1,24 +1,23 @@
|
||||||
virtual-dsm
|
docker-qemu
|
||||||
=============
|
=============
|
||||||
|
|
||||||
[![build_img]][build_url]
|
[![build_img]][build_url]
|
||||||
[![gh_last_release_svg]][dsm-docker-hub]
|
[![gh_last_release_svg]][qemu-docker-hub]
|
||||||
[![Docker Image Size]][dsm-docker-hub]
|
[![Docker Image Size]][qemu-docker-hub]
|
||||||
[![Docker Pulls Count]][dsm-docker-hub]
|
[![Docker Pulls Count]][qemu-docker-hub]
|
||||||
|
|
||||||
[build_url]: https://github.com/kroese/virtual-dsm/actions
|
[build_url]: https://github.com/kroese/docker-qemu/actions
|
||||||
[dsm-docker-hub]: https://hub.docker.com/r/kroese/virtual-dsm
|
[qemu-docker-hub]: https://hub.docker.com/r/kroese/docker-qemu
|
||||||
|
|
||||||
[build_img]: https://github.com/kroese/virtual-dsm/actions/workflows/build.yml/badge.svg
|
[build_img]: https://github.com/kroese/docker-qemu/actions/workflows/build.yml/badge.svg
|
||||||
[Docker Image Size]: https://img.shields.io/docker/image-size/kroese/virtual-dsm/latest
|
[Docker Image Size]: https://img.shields.io/docker/image-size/kroese/docker-qemu/latest
|
||||||
[Docker Pulls Count]: https://img.shields.io/docker/pulls/kroese/virtual-dsm.svg?style=flat
|
[Docker Pulls Count]: https://img.shields.io/docker/pulls/kroese/docker-qemu.svg?style=flat
|
||||||
[gh_last_release_svg]: https://img.shields.io/docker/v/kroese/virtual-dsm?arch=amd64&sort=date
|
[gh_last_release_svg]: https://img.shields.io/docker/v/kroese/docker-qemu?arch=amd64&sort=date
|
||||||
|
|
||||||
A docker container of Virtual DSM v7.2
|
A docker container of QEMU
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
- Upgrades supported
|
|
||||||
- KVM acceleration
|
- KVM acceleration
|
||||||
- Graceful shutdown
|
- Graceful shutdown
|
||||||
|
|
||||||
|
@ -31,16 +30,16 @@ version: "3"
|
||||||
services:
|
services:
|
||||||
vm:
|
vm:
|
||||||
container_name: dsm
|
container_name: dsm
|
||||||
image: kroese/virtual-dsm:latest
|
image: kroese/docker-qemu:latest
|
||||||
environment:
|
environment:
|
||||||
DISK_SIZE: "16G"
|
DISK_SIZE: "16G"
|
||||||
|
BOOT: "https://ftp.halifax.rwth-aachen.de/osdn/clonezilla/78259/clonezilla-live-3.0.3-22-amd64.iso"
|
||||||
devices:
|
devices:
|
||||||
- /dev/kvm
|
- /dev/kvm
|
||||||
cap_add:
|
cap_add:
|
||||||
- NET_ADMIN
|
- NET_ADMIN
|
||||||
ports:
|
ports:
|
||||||
- 5000:5000
|
- 22:22
|
||||||
- 5001:5001
|
|
||||||
restart: on-failure
|
restart: on-failure
|
||||||
stop_grace_period: 60s
|
stop_grace_period: 60s
|
||||||
```
|
```
|
||||||
|
@ -48,7 +47,7 @@ services:
|
||||||
Via `docker run`
|
Via `docker run`
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker run -p 5000:5000 --device=/dev/kvm --cap-add NET_ADMIN --stop-timeout 60 kroese/virtual-dsm:latest
|
docker run -p 22:22 --device=/dev/kvm --cap-add NET_ADMIN --stop-timeout 60 kroese/docker-qemu:latest
|
||||||
```
|
```
|
||||||
|
|
||||||
## FAQ
|
## FAQ
|
||||||
|
@ -118,15 +117,3 @@ docker run -p 5000:5000 --device=/dev/kvm --cap-add NET_ADMIN --stop-timeout 60
|
||||||
```
|
```
|
||||||
|
|
||||||
You can also switch back and forth between versions this way without loosing your file data.
|
You can also switch back and forth between versions this way without loosing your file data.
|
||||||
|
|
||||||
* ### What are the differences compared to standard DSM? ###
|
|
||||||
|
|
||||||
There are only three minor differences: the Virtual Machine Manager package is not available, Surveillance Station does not include any free licenses, and logging in to your Synology account is not supported.
|
|
||||||
|
|
||||||
## Acknowledgments
|
|
||||||
|
|
||||||
Based on an [article](https://jxcn.org/2022/04/vdsm-first-try/) by JXCN.
|
|
||||||
|
|
||||||
## Disclaimer
|
|
||||||
|
|
||||||
Only run this container on original Synology hardware, any other use is not permitted and might not be legal.
|
|
||||||
|
|
9
run.sh
9
run.sh
|
@ -2,7 +2,7 @@
|
||||||
set -eu
|
set -eu
|
||||||
|
|
||||||
if /run/install.sh; then
|
if /run/install.sh; then
|
||||||
echo "Starting Virtual DSM..."
|
echo "Starting QEMU..."
|
||||||
else
|
else
|
||||||
echo "Installation failed (code $?)" && exit 81
|
echo "Installation failed (code $?)" && exit 81
|
||||||
fi
|
fi
|
||||||
|
@ -15,9 +15,10 @@ source /run/network.sh
|
||||||
|
|
||||||
[ -z "${KVM_NET_OPTS}" ] && echo "Error: Failed to setup network..." && exit 84
|
[ -z "${KVM_NET_OPTS}" ] && echo "Error: Failed to setup network..." && exit 84
|
||||||
|
|
||||||
source /run/serial.sh
|
KVM_SERIAL_OPTS="\
|
||||||
|
-serial mon:stdio \
|
||||||
[ -z "${KVM_SERIAL_OPTS}" ] && echo "Error: Failed to setup serial..." && exit 85
|
-device virtio-serial-pci,id=virtio-serial0,bus=pcie.0,addr=0x3 \
|
||||||
|
-chardev pty,id=charserial0"
|
||||||
|
|
||||||
source /run/power.sh
|
source /run/power.sh
|
||||||
|
|
||||||
|
|
55
serial.sh
55
serial.sh
|
@ -1,55 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# Docker environment variabeles
|
|
||||||
: ${HOST_SERIAL:=''}
|
|
||||||
: ${GUEST_SERIAL:=''}
|
|
||||||
|
|
||||||
permanent="DSM"
|
|
||||||
serialstart="2000"
|
|
||||||
|
|
||||||
[ ! -d "$IMG" ] && echo "Storage folder (${IMG}) not found!" && exit 69
|
|
||||||
|
|
||||||
#If environment variabele not set fall back to file
|
|
||||||
if [ -z "$HOST_SERIAL" ]; then
|
|
||||||
FILE="${IMG}/host.serial"
|
|
||||||
if [ ! -f "$FILE" ]; then
|
|
||||||
SERIAL="$(echo "$serialstart" | tr ' ' '\n' | sort -R | tail -1)$permanent"$(printf "%06d" $((RANDOM % 30000 + 1)))
|
|
||||||
echo $SERIAL > "$FILE"
|
|
||||||
fi
|
|
||||||
HOST_SERIAL=$(cat "${FILE}")
|
|
||||||
fi
|
|
||||||
|
|
||||||
#If environment variabele not set fall back to file
|
|
||||||
if [ -z "$GUEST_SERIAL" ]; then
|
|
||||||
FILE="${IMG}/guest.serial"
|
|
||||||
if [ ! -f "$FILE" ]; then
|
|
||||||
SERIAL="$(echo "$serialstart" | tr ' ' '\n' | sort -R | tail -1)$permanent"$(printf "%06d" $((RANDOM % 30000 + 1)))
|
|
||||||
echo $SERIAL > "$FILE"
|
|
||||||
fi
|
|
||||||
GUEST_SERIAL=$(cat "${FILE}")
|
|
||||||
fi
|
|
||||||
|
|
||||||
CPU=$(lscpu | sed -nr '/Model name/ s/.*:\s*(.*) @ .*/\1/p' | sed ':a;s/ / /;ta' | sed s/"(R)"//g | sed s/"-"//g | sed 's/[^[:alnum:] ]\+//g')
|
|
||||||
|
|
||||||
if [ -n "$CPU" ]; then
|
|
||||||
CPU="$CPU,,"
|
|
||||||
else
|
|
||||||
CPU="QEMU, Virtual CPU, X86_64"
|
|
||||||
fi
|
|
||||||
|
|
||||||
./run/serial.bin -cpu="${CPU_CORES}" \
|
|
||||||
-cpu_arch="${CPU}" \
|
|
||||||
-buildnumber=42962 \
|
|
||||||
-vmmts=1679863686 \
|
|
||||||
-hostsn="${HOST_SERIAL}" \
|
|
||||||
-guestsn="${GUEST_SERIAL}" \
|
|
||||||
-vmmversion="2.6.1-12139" \
|
|
||||||
-guestuuid="ba13a19a-c0c1-4fef-9346-915ed3b98341" > /dev/null 2>&1 &
|
|
||||||
|
|
||||||
KVM_SERIAL_OPTS="\
|
|
||||||
-serial mon:stdio \
|
|
||||||
-device virtio-serial-pci,id=virtio-serial0,bus=pcie.0,addr=0x3 \
|
|
||||||
-chardev pty,id=charserial0 \
|
|
||||||
-device isa-serial,chardev=charserial0,id=serial0 \
|
|
||||||
-chardev socket,id=charchannel0,host=127.0.0.1,port=12345,reconnect=10 \
|
|
||||||
-device virtserialport,bus=virtio-serial0.0,nr=1,chardev=charchannel0,id=channel0,name=vchannel"
|
|
|
@ -1,6 +0,0 @@
|
||||||
// vdsm-serial project doc.go
|
|
||||||
|
|
||||||
/*
|
|
||||||
vdsm-serial document
|
|
||||||
*/
|
|
||||||
package main
|
|
|
@ -1,4 +0,0 @@
|
||||||
module vdsm-serial
|
|
||||||
|
|
||||||
go 1.20
|
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
|
|
263
serial/main.go
263
serial/main.go
|
@ -1,263 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"encoding/binary"
|
|
||||||
"flag"
|
|
||||||
"fmt"
|
|
||||||
"log"
|
|
||||||
"net"
|
|
||||||
"strconv"
|
|
||||||
"net/http"
|
|
||||||
"math/rand"
|
|
||||||
"github.com/gorilla/mux"
|
|
||||||
)
|
|
||||||
|
|
||||||
type REQ struct {
|
|
||||||
RandID int64
|
|
||||||
GuestUUID [16]byte
|
|
||||||
GuestID int64
|
|
||||||
IsReq int32
|
|
||||||
IsResp int32
|
|
||||||
NeedResponse int32
|
|
||||||
ReqLength int32
|
|
||||||
RespLength int32
|
|
||||||
CommandID int32
|
|
||||||
SubCommand int32
|
|
||||||
Reserve int32
|
|
||||||
}
|
|
||||||
|
|
||||||
var HostSN = flag.String("hostsn", "0000000000000", "Host SN, 13 bytes")
|
|
||||||
var GuestSN = flag.String("guestsn", "0000000000000", "Guest SN, 13 bytes")
|
|
||||||
var GuestUUID = flag.String("guestuuid", "ba13a19a-c0c1-4fef-9346-915ed3b98341", "Guest UUID")
|
|
||||||
var GuestCPUs = flag.Int("cpu", 1, "Num of Guest cpu")
|
|
||||||
var GuestCPU_ARCH = flag.String("cpu_arch", "QEMU, Virtual CPU, X86_64", "CPU arch")
|
|
||||||
var HostDSMBuildNumber = flag.Int("buildnumber", 42962, "Build Number of Host")
|
|
||||||
var HostDSMfixNumber = flag.Int("fixNumber", 0, "Fix Number of Host")
|
|
||||||
var VMMVersion = flag.String("vmmversion", "2.6.1-12139", "VMM version")
|
|
||||||
var VMMTimestamp = flag.Int("vmmts", 1679863686, "VMM Timestamp")
|
|
||||||
var Cluster_UUID = "3bdea92b-68f4-4fe9-aa4b-d645c3c63864"
|
|
||||||
|
|
||||||
var ApiPort = flag.String("api", ":2210", "API port")
|
|
||||||
var ListenAddr = flag.String("addr", "0.0.0.0:12345", "Listen address")
|
|
||||||
|
|
||||||
var LastConnection net.Conn
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
|
|
||||||
flag.Parse()
|
|
||||||
|
|
||||||
r := mux.NewRouter()
|
|
||||||
r.HandleFunc("/", home)
|
|
||||||
r.HandleFunc("/write", write)
|
|
||||||
go http.ListenAndServe(*ApiPort, r)
|
|
||||||
|
|
||||||
listener, err := net.Listen("tcp", *ListenAddr)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
log.Println("Error listening", err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Println("Start listen on " + *ListenAddr)
|
|
||||||
|
|
||||||
for {
|
|
||||||
conn, err := listener.Accept()
|
|
||||||
if err != nil {
|
|
||||||
log.Println("Error on accept", err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
log.Printf("New connection from %s\n", conn.RemoteAddr().String())
|
|
||||||
|
|
||||||
go incoming_conn(conn)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func incoming_conn(conn net.Conn) {
|
|
||||||
|
|
||||||
LastConnection = conn
|
|
||||||
|
|
||||||
for {
|
|
||||||
buf := make([]byte, 4096)
|
|
||||||
len, err := conn.Read(buf)
|
|
||||||
if err != nil {
|
|
||||||
log.Println("Error on read", err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if len != 4096 {
|
|
||||||
log.Printf("Read %d Bytes, not 4096\n", len)
|
|
||||||
// something wrong, close and wait for reconnect
|
|
||||||
conn.Close()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
go process_req(buf, conn)
|
|
||||||
//log.Printf("Read %d Bytes\n%#v\n", len, string(buf[:len]))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var commandsName = map[int]string{
|
|
||||||
3: "Guest Power info",
|
|
||||||
4: "Host DSM version",
|
|
||||||
5: "Guest SN",
|
|
||||||
7: "Guest CPU info",
|
|
||||||
9: "Host DSM version",
|
|
||||||
8: "VMM version",
|
|
||||||
10: "Get Guest Info",
|
|
||||||
11: "Guest UUID",
|
|
||||||
12: "Cluster UUID",
|
|
||||||
13: "Host SN",
|
|
||||||
16: "Update Deadline",
|
|
||||||
17: "Guest Timestamp",
|
|
||||||
}
|
|
||||||
|
|
||||||
func process_req(buf []byte, conn net.Conn) {
|
|
||||||
var req REQ
|
|
||||||
var data string
|
|
||||||
err := binary.Read(bytes.NewReader(buf), binary.LittleEndian, &req)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Error on decode %s\n", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if req.IsReq == 1 {
|
|
||||||
data = string(buf[64 : 64+req.ReqLength])
|
|
||||||
} else if req.IsResp == 1 {
|
|
||||||
data = string(buf[64 : 64+req.RespLength])
|
|
||||||
}
|
|
||||||
|
|
||||||
// log.Printf("%#v\n", req)
|
|
||||||
log.Printf("Command: %s from Guest:%d \n", commandsName[int(req.CommandID)], req.GuestID)
|
|
||||||
if data != "" {
|
|
||||||
log.Printf("Info: %s\n", data)
|
|
||||||
}
|
|
||||||
// Hard code of command
|
|
||||||
switch req.CommandID {
|
|
||||||
case 3:
|
|
||||||
// Guest start/reboot
|
|
||||||
case 4:
|
|
||||||
// Host DSM version
|
|
||||||
data = fmt.Sprintf(`{"buildnumber":%d,"smallfixnumber":%d}`, *HostDSMBuildNumber, *HostDSMfixNumber)
|
|
||||||
case 5:
|
|
||||||
// Guest SN
|
|
||||||
data = *GuestSN
|
|
||||||
case 7:
|
|
||||||
// CPU info
|
|
||||||
// {"cpuinfo":"QEMU, Virtual CPU, X86_64, 1" "vcpu_num":1}
|
|
||||||
data = fmt.Sprintf(`{"cpuinfo":"%s","vcpu_num":%d}`,
|
|
||||||
*GuestCPU_ARCH+", "+strconv.Itoa(*GuestCPUs), *GuestCPUs)
|
|
||||||
case 8:
|
|
||||||
data = fmt.Sprintf(`{"id":"Virtualization","name":"Virtual Machine Manager","timestamp":%d,"version":"%s"}`,
|
|
||||||
*VMMTimestamp, *VMMVersion)
|
|
||||||
case 9:
|
|
||||||
// Version Info
|
|
||||||
case 10:
|
|
||||||
// Guest Info
|
|
||||||
case 11:
|
|
||||||
// Guest UUID
|
|
||||||
data = *GuestUUID
|
|
||||||
case 12:
|
|
||||||
// cluster UUID
|
|
||||||
data = Cluster_UUID
|
|
||||||
case 13:
|
|
||||||
// Host SN
|
|
||||||
data = *HostSN
|
|
||||||
case 16:
|
|
||||||
// Update Dead line time, always 0x7fffffffffffffff
|
|
||||||
data = "9223372036854775807"
|
|
||||||
case 17:
|
|
||||||
// TimeStamp
|
|
||||||
default:
|
|
||||||
log.Printf("No handler for this command %d\n", req.CommandID)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// if it's a req and need response
|
|
||||||
if req.IsReq == 1 && req.NeedResponse == 1 {
|
|
||||||
buf = make([]byte, 0, 4096)
|
|
||||||
writer := bytes.NewBuffer(buf)
|
|
||||||
req.IsResp = 1
|
|
||||||
req.IsReq = 0
|
|
||||||
req.ReqLength = 0
|
|
||||||
req.RespLength = int32(len([]byte(data)) + 1)
|
|
||||||
log.Printf("Response data: %s\n", data)
|
|
||||||
|
|
||||||
// write to buf
|
|
||||||
binary.Write(writer, binary.LittleEndian, &req)
|
|
||||||
writer.Write([]byte(data))
|
|
||||||
res := writer.Bytes()
|
|
||||||
// full fill 4096
|
|
||||||
buf = make([]byte, 4096, 4096)
|
|
||||||
copy(buf, res)
|
|
||||||
conn.Write(buf)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func home(w http.ResponseWriter, r *http.Request) {
|
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
|
||||||
w.Write([]byte(`{"status": "error", "data": null, "message": "No command specified"}`))
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
func write(w http.ResponseWriter, r *http.Request) {
|
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
|
||||||
|
|
||||||
var err error
|
|
||||||
var commandID int
|
|
||||||
|
|
||||||
query := r.URL.Query()
|
|
||||||
commandID, err = strconv.Atoi(query.Get("command"))
|
|
||||||
|
|
||||||
if (err != nil || commandID < 1) {
|
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
|
||||||
w.Write([]byte(`{"status": "error", "data": null, "message": "Invalid command ID"}`))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (send_command((int32)(commandID), 1) == false) {
|
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
|
||||||
w.Write([]byte(`{"status": "error", "data": null, "message": "Failed to send command"}`))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
w.WriteHeader(http.StatusOK)
|
|
||||||
w.Write([]byte(`{"status": "success", "data": null, "message": null}`))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func send_command(CommandID int32, SubCommand int32) bool {
|
|
||||||
|
|
||||||
var req REQ
|
|
||||||
|
|
||||||
req.CommandID = CommandID
|
|
||||||
req.SubCommand = SubCommand
|
|
||||||
|
|
||||||
req.IsReq = 1
|
|
||||||
req.IsResp = 0
|
|
||||||
req.ReqLength = 0
|
|
||||||
req.RespLength = 0
|
|
||||||
req.NeedResponse = 0
|
|
||||||
req.GuestID = 10000000
|
|
||||||
req.RandID = rand.Int63()
|
|
||||||
|
|
||||||
var buf = make([]byte, 0, 4096)
|
|
||||||
var writer = bytes.NewBuffer(buf)
|
|
||||||
|
|
||||||
// write to buf
|
|
||||||
binary.Write(writer, binary.LittleEndian, &req)
|
|
||||||
res := writer.Bytes()
|
|
||||||
|
|
||||||
// full fill 4096
|
|
||||||
buf = make([]byte, 4096, 4096)
|
|
||||||
copy(buf, res)
|
|
||||||
|
|
||||||
//log.Printf("Writing command %d\n", CommandID)
|
|
||||||
|
|
||||||
if (LastConnection == nil) { return false }
|
|
||||||
|
|
||||||
LastConnection.Write(buf)
|
|
||||||
return true
|
|
||||||
|
|
||||||
}
|
|
11
server.sh
11
server.sh
|
@ -1,11 +0,0 @@
|
||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
set -eu
|
|
||||||
|
|
||||||
HTML="<HTML><BODY><H1><CENTER>Please wait while Virtual DSM is installing...</CENTER></H1></BODY></HTML>"
|
|
||||||
RESPONSE="HTTP/1.1 200 OK\r\nConnection: close\r\n\r\n$HTML\r\n"
|
|
||||||
|
|
||||||
while { echo -en "$RESPONSE"; } | nc -lN "${1:-8080}"; do
|
|
||||||
echo "================================================"
|
|
||||||
done
|
|
||||||
|
|
Loading…
Reference in a new issue