Last active
April 2, 2024 22:10
-
-
Save ugoenyioha/5ab9e117405b8d3fcde6c71732e6cdd1 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/sh | |
# | |
# Ubuntu chroot environment installer script for Synology routers | |
# Hard-float - VFPv3-D16 | |
# Tested only on RT2600ac in Wireless Router mode | |
# | |
# 2019-2023, Krisztián Kende <krisztiankende@gmail.com> | |
# | |
# This script can be used freely at your own risk. | |
# I will not take any responsibility! | |
# | |
# | |
# Compatible Ubuntu distributions: 18.04.5 LTS | |
# | |
vers=1.27 # 2023.02.02 | |
syno_routers="RT6600ax WRX560 MR2200ac RT2600ac" # Supported models | |
error() | |
{ | |
printf "\e[2J\e[1;1H\ec\n \e[1;31m" | |
case $1 in | |
1) | |
printf "Permission denied!\n Please try again with 'root' user, instead of '$(whoami)'." | |
;; | |
2) | |
printf "The requested removal operation is in progress!\n Please wait about 5 minutes and try again." | |
;; | |
3) | |
printf "Sorry, but failed to detect any compatible Synology router!" | |
;; | |
4) | |
printf "Sorry, but failed to detect the internet connection!" | |
;; | |
5) | |
printf "A Ubuntu chroot environment is already active!\n Please shut it down before creating a new one.\n\n BE CAREFUL, do not delete the Ubuntu directory!\n Run this script again and select the option 4." | |
;; | |
6) | |
printf "Sorry, but failed to detect any compatible ext4 partition!" | |
;; | |
7) | |
printf "Sorry, but not enough free space to prepare the Ubuntu chroot environment!" | |
;; | |
8) | |
printf "Sorry, but failed to detect any existing Ubuntu installation!" | |
;; | |
9) | |
printf "Failed to detect any modifications in the router internal filesystem!" | |
esac | |
printf "\n\n The script is ended without any effect!\e[0m\n\n" | |
exit $1 | |
} >&2 | |
errd() | |
{ | |
printf "\n \e[1;31mSorry, but failed to download an essential file!\e[0m\n\n" | |
exit 9 | |
} >&2 | |
setup() | |
{ | |
grep -q "^alias uroot=\"chroot /ubuntu /bin/bash\"$" /root/.profile || cat << EOF >>/root/.profile | |
alias uroot="chroot /ubuntu /bin/bash" | |
alias apt="chroot /ubuntu /usr/bin/apt" | |
alias apt-upgrade="apt update ; apt full-upgrade ; apt autoremove --purge ; apt clean" | |
EOF | |
sfile=/usr/local/etc/rc.d/ubuntu.sh | |
csum=9bdc3d3cdcd06d5dd550ca5620abbb1e # Avoid unnecessary write operations on the internal eMMC chip | |
if [ -s $sfile ] && [ "$(python -c "import hashlib ; print(hashlib.md5(open('$sfile', 'rb').read()).hexdigest())")" = "$csum" ] # 'md5sum' is missing from the router system | |
then touch -m $sfile # Close the already running startup script | |
else cat << EOF >$sfile # Internal SWAP priority is 999 | |
#!/bin/sh | |
ubuntu() | |
{ | |
lmt="\$(date -ur $sfile)" | |
tout=30 | |
while : | |
do | |
for dir in /volumeUSB* | |
do | |
for mp in \$dir/* | |
do | |
[ -f \$mp/ubuntu/bin/bash ] && [ "\${1:0:10}" != /volumeUSB -o "\$mp" = "\$1" ] || continue | |
[ ! -h /ubuntu ] || [ "\$(readlink /ubuntu)" != "\$mp/ubuntu" ] && { | |
rm -rf /ubuntu | |
ln -s \$mp/ubuntu /ubuntu | |
} | |
grep "/ubuntu/dev " /proc/mounts || { | |
mount -t devtmpfs -o rw,nosuid,relatime,mode=755 dev /ubuntu/dev | |
mount -t devpts -o rw,nosuid,noexec,relatime,gid=5,mode=620,ptmxmode=000 pts /ubuntu/dev/pts | |
mount -t tmpfs -o rw,nosuid,nodev,relatime shm /ubuntu/dev/shm | |
mount -t proc proc /ubuntu/proc | |
mount -t tmpfs -o rw,nosuid,noexec,relatime,mode=755 run /ubuntu/run | |
mount -t sysfs sys /ubuntu/sys | |
mount -t debugfs debug /ubuntu/sys/kernel/debug | |
mount -t securityfs security /ubuntu/sys/kernel/security | |
mount -t tmpfs tmp /ubuntu/tmp | |
mount --bind / /ubuntu/mnt/Synology | |
mount --bind /volume1 /ubuntu/mnt/Internal | |
mount --bind \$mp /ubuntu/mnt/HDD | |
[ -e /ubuntu/swapfile ] && swapon -p 1000 /ubuntu/swapfile | |
} | |
for a in /ubuntu/autostart/* | |
do [ -x \$a ] && chroot /ubuntu "\${a:7}" | |
done | |
exit 0 | |
done | |
done | |
[ \$((tout--)) -eq 0 ] && break | |
sleep 10s | |
[ "\$(date -ur $sfile)" = "\$lmt" ] || break | |
done | |
} | |
[ "\$1" = start ] && ubuntu \$2 >/dev/null 2>&1 & | |
EOF | |
fi | |
[ -x $sfile ] || chmod +x $sfile | |
setsid $sfile start $1 | |
until | |
sleep 1s | |
[ -f /ubuntu/usr/bin/apt ] && [ "$(readlink /ubuntu)" = "$1/ubuntu" ] | |
do : | |
done | |
chroot /ubuntu /usr/bin/apt update | |
chroot /ubuntu /usr/bin/apt full-upgrade -y | |
chroot /ubuntu /usr/bin/apt install locales -y | |
chroot /ubuntu /usr/bin/apt autoremove --purge -y | |
chroot /ubuntu /usr/bin/apt clean | |
[ -f /ubuntu/usr/sbin/locale-gen ] || errd | |
chroot /ubuntu /usr/sbin/locale-gen en_US.UTF-8 | |
sync | |
printf "\e[2J\e[1;1H\ec\n \e[1mOkay, all done!\n\n The chroot environment (alias 'uroot') is ready,\n just perform a logout from this SSH session, and login again.\e[0m\n\n" | |
exit 0 | |
} | |
remove() | |
{ | |
[ -h /ubuntu ] || [ -f /usr/local/etc/rc.d/ubuntu.sh ] || grep -qe "^alias uroot=" -e "^alias apt=" -e "^alias apt-upgrade=" /root/.profile || { | |
[ "$1" ] && return || error 9 | |
} | |
rm /ubuntu /usr/local/etc/rc.d/ubuntu.sh | |
sed -ie "/^alias uroot=/d" -e "/^alias apt=/d" -e "/^alias apt-upgrade=/d" /root/.profile | |
sync | |
} | |
[ $(id -u) -eq 0 ] || error 1 | |
[ -e /usr/local/etc/rc.d/ubuntu_remove.sh ] && error 2 | |
egrep -sq $(printf "$syno_routers" | sed -e s/^/^/ -e "s/ /|^/g") /proc/sys/kernel/syno_hw_version || error 3 | |
ping -c 1 www.google.com >/dev/null 2>&1 || error 4 | |
printf "\e[2J\e[1;1H\ec\n\e[1mUbuntu installer script for Synology routers v$vers by Kendek\n\n 1\e[0m - Install and setup a new Ubuntu chroot environment\n \e[1m2\e[0m - Setup the existing Ubuntu directory\n \e[1m3\e[0m - Remove all modifications from the router internal filesystem\n \e[1m4\e[0m - Completely remove the Ubuntu chroot environment and reboot the router\n \e[1m0\e[0m - Quit (default)\n\n" | |
while : | |
do | |
read -p "Select an option [0-4]: " o | |
case $o in | |
1) | |
mlst="$(mount)" | |
printf "$mlst" | grep -q " /ubuntu/" && error 5 | |
mlst="$(printf "$mlst" | grep /volumeUSB.*ext4 | cut -d " " -f 3)" # Compatible only with ext4 | |
[ "$mlst" ] || error 6 | |
[ $(echo "$mlst" | wc -l) -eq 1 ] && mp=$mlst || { | |
cnt=0 | |
for mp in $mlst | |
do [ $((++cnt)) -eq 1 ] && mpts=" \e[1m1\e[0m - $mp/ubuntu (default)" || mpts="$mpts\n \e[1m$cnt\e[0m - $mp/ubuntu" | |
done | |
printf "\n Place to install:\n\n$mpts\n\n" | |
mp="" | |
while : | |
do | |
read -p "Select an option [1-$cnt]: " o | |
[ "$o" ] || o=1 | |
for i in $(seq 1 $cnt) | |
do [ "$i" = "$o" ] && { | |
mp=$(echo "$mlst" | sed -n ${i}p) | |
break | |
} | |
done | |
[ "$mp" ] && break | |
done | |
} | |
[ $(df $mp | awk "NR==2 {printf \$4}") -lt 1572864 ] && error 7 # 1.5 GiB free space check | |
printf "\n Ubuntu version:\n\n \e[1m1\e[0m - 18.04.5 LTS Bionic Beaver (default)\n\n" | |
while : | |
do | |
read -p "Select an option [1]: " o | |
case $o in | |
""|1) | |
vers=22.04.4 | |
name=jammy | |
;; | |
*) | |
continue | |
esac | |
break | |
done | |
udir=$mp/ubuntu # Install directory on the external device | |
[ -e $udir ] && mv $udir ${udir}_$(tr -dc a-zA-Z0-9 </dev/urandom | head -c 16) # Backup the existing data | |
mkdir $udir | |
cd $udir | |
wget -O ubuntu.tar.gz http://cdimage.ubuntu.com/ubuntu-base/releases/$vers/release/ubuntu-base-$vers-base-arm$([ "$rname" = RT6600ax ] && printf 64 || printf hf).tar.gz || errd | |
tar -xf ubuntu.tar.gz | |
rm ubuntu.tar.gz | |
cat << EOF >etc/apt/sources.list | |
deb http://ports.ubuntu.com/ubuntu-ports $name main multiverse restricted universe | |
deb http://ports.ubuntu.com/ubuntu-ports $name-security main multiverse restricted universe | |
deb http://ports.ubuntu.com/ubuntu-ports $name-updates main multiverse restricted universe | |
deb http://ports.ubuntu.com/ubuntu-ports $name-backports main multiverse restricted universe | |
EOF | |
mkdir autostart mnt/HDD mnt/Internal mnt/Synology # The files in 'autostart' directory are automatically executed when the router is started | |
rm -f etc/resolv.conf etc/localtime # Required for internet connection and local time (OpenVPN log) | |
ln -s /mnt/Synology/etc/resolv.conf etc/resolv.conf | |
ln -s /mnt/Synology/etc/localtime etc/localtime | |
while read -n 1 -t 1 ; do : ; done # Flush input buffer | |
printf "\e[2J\e[1;1H\ec\n Create swapfile:\n\n \e[1m1\e[0m - 256 MiB\n \e[1m2\e[0m - 512 MiB (default)\n \e[1m3\e[0m - 1 GiB\n \e[1m4\e[0m - None\n\n" | |
while : | |
do | |
read -p "Select an option [1-4]: " o | |
[ "$o" = 4 ] || { | |
case $o in | |
1) | |
size=256 | |
;; | |
""|2) | |
size=512 | |
;; | |
3) | |
size=1024 | |
;; | |
*) | |
continue | |
esac | |
hdparm --fallocate $(( $size * 1024 )) swapfile # Use fallocate for fast allocation | |
chmod 0600 swapfile | |
mkswap swapfile | |
} | |
break | |
done | |
setup $mp | |
;; | |
2) | |
for dir in /volumeUSB* | |
do | |
for mp in $dir/* | |
do [ -f $mp/ubuntu/bin/bash ] && setup $mp | |
done | |
done | |
error 8 | |
;; | |
3) | |
remove | |
printf "\e[2J\e[1;1H\ec\n \e[1mOkay, all done!\n\n The services have not been stopped, the Ubuntu directory is still intact.\n\n Please reboot the router before delete anything.\e[0m\n\n" | |
exit 0 | |
;; | |
4) | |
sfile=/usr/local/etc/rc.d/ubuntu_remove.sh # Startup script for removing the Ubuntu directory from the external device | |
cat << EOF >$sfile | |
#!/bin/sh | |
remove() | |
{ | |
tout=30 | |
while : | |
do | |
for dir in /volumeUSB* | |
do | |
for mp in \$dir/* | |
do | |
[ -f \$mp/ubuntu/bin/bash ] || continue | |
udir=\$mp/ubuntu_\$(tr -dc a-zA-Z0-9 </dev/urandom | head -c 16) | |
mv \$mp/ubuntu \$udir | |
rm -rf \$udir | |
return | |
done | |
done | |
[ \$((tout--)) -eq 0 ] && break | |
sleep 10s | |
done | |
} | |
[ "\$1" = start ] && { | |
remove | |
rm $sfile | |
sync | |
} >/dev/null 2>&1 & | |
EOF | |
chmod +x $sfile | |
remove - | |
printf "\e[2J\e[1;1H\ec\n \e[1mThe router is rebooting now...\n\n Please do not unplug the external storage device(s).\e[0m\n\n" | |
reboot | |
exit 0 | |
;; | |
""|0) | |
echo | |
exit 0 | |
esac | |
done |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment