2019-04-09 15:51:15 +08:00
|
|
|
#!/bin/bash
|
2019-04-09 15:54:26 +08:00
|
|
|
set -Eeuo pipefail
|
2020-03-20 23:15:31 +08:00
|
|
|
# disable command path hashing as we are going to move fast and break things
|
|
|
|
set +h
|
2019-04-09 15:51:15 +08:00
|
|
|
|
|
|
|
WORKDIR="/tmp/menhera"
|
2022-11-25 22:05:44 +08:00
|
|
|
MIRROR="https://iso.meson.cc/ultralite/archlinux"
|
2021-03-01 13:03:20 +08:00
|
|
|
ROOTFS="${MIRROR}/iso/latest/arch/x86_64/airootfs.sfs"
|
2019-04-09 15:51:15 +08:00
|
|
|
|
|
|
|
# internal global variables
|
|
|
|
OLDROOT="/"
|
|
|
|
NEWROOT=""
|
|
|
|
|
2022-11-25 22:31:34 +08:00
|
|
|
[[ "$(uname -m)" == "x86_64" ]] || { echo "error: wrong arch $(uname -m) (not x86_64)"; exit 1; }
|
2020-09-10 18:12:22 +08:00
|
|
|
|
2022-11-25 22:31:34 +08:00
|
|
|
PUBKEY="./key.pub"
|
|
|
|
[ -f "$PUBKEY" ] || { echo "error: you should put your ssh public key at ${PUBKEY} in order to ssh with root account and this key later"; exit 1; }
|
2020-01-07 19:51:22 +08:00
|
|
|
|
2022-11-25 22:31:34 +08:00
|
|
|
if [[ $EUID -ne 0 ]]; then
|
|
|
|
echo "This script must be run as root"
|
|
|
|
exit 1
|
|
|
|
fi
|
2019-04-13 11:05:42 +08:00
|
|
|
|
2022-11-25 22:31:34 +08:00
|
|
|
systemctl status > /dev/null || { echo "error: no systemd"; exit 1; }
|
2019-04-13 11:05:42 +08:00
|
|
|
|
|
|
|
# helper functions
|
2019-04-09 15:51:15 +08:00
|
|
|
# https://stackoverflow.com/a/3232082/2646069
|
2019-09-01 22:46:31 +08:00
|
|
|
menhera::confirm() {
|
2019-04-09 15:51:15 +08:00
|
|
|
# call with a prompt string or use a default
|
|
|
|
read -r -p "${1:-Are you sure? [y/N]} " response
|
|
|
|
case "$response" in
|
2022-11-25 22:31:34 +08:00
|
|
|
[yY][eE][sS]|[yY])
|
2019-04-09 15:51:15 +08:00
|
|
|
true
|
|
|
|
;;
|
|
|
|
*)
|
|
|
|
false
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
}
|
|
|
|
|
2022-11-25 22:31:34 +08:00
|
|
|
echo -e "We will start a temporary RAM system as your recovery environment."
|
|
|
|
echo -e "Note that this script will kill programs and umount filesystems without prompting."
|
|
|
|
echo -e "Please confirm:"
|
|
|
|
echo -e "\tYou have closed all programs you can, and backed up all important data"
|
|
|
|
echo -e "\tYou can SSH into your system as root user"
|
|
|
|
menhera::confirm || exit -1
|
2019-04-09 17:59:37 +08:00
|
|
|
|
2022-11-25 22:31:34 +08:00
|
|
|
# fix possible PATH problems
|
|
|
|
export PATH="$PATH:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
2021-03-01 13:03:20 +08:00
|
|
|
|
2022-11-25 22:31:34 +08:00
|
|
|
echo "Loading kernel modules..."
|
|
|
|
modprobe overlay
|
|
|
|
modprobe squashfs
|
|
|
|
sysctl kernel.panic=10
|
|
|
|
|
|
|
|
echo "Creating workspace in '${WORKDIR}'..."
|
|
|
|
# workspace
|
|
|
|
mkdir -p "${WORKDIR}"
|
|
|
|
mount -t tmpfs -o size=100% tmpfs "${WORKDIR}"
|
|
|
|
|
|
|
|
mkdir -p "${WORKDIR}/newroot" # where iso is stored
|
|
|
|
mkdir -p "${WORKDIR}/newrootro" # lower
|
|
|
|
mkdir -p "${WORKDIR}/newrootrw" # upper
|
|
|
|
mkdir -p "${WORKDIR}/overlayfs_workdir" # work
|
|
|
|
|
|
|
|
echo "Downloading temporary rootfs..."
|
|
|
|
wget -O "${WORKDIR}/rootfs.squashfs" "${ROOTFS}"
|
|
|
|
|
|
|
|
echo "Mounting temporary rootfs..."
|
|
|
|
mount -t squashfs "${WORKDIR}/rootfs.squashfs" "${WORKDIR}/newrootro"
|
|
|
|
mount -t overlay overlay -o rw,lowerdir="${WORKDIR}/newrootro",upperdir="${WORKDIR}/newrootrw",workdir="${WORKDIR}/overlayfs_workdir" "${WORKDIR}/newroot"
|
|
|
|
NEWROOT="${WORKDIR}/newroot"
|
|
|
|
|
|
|
|
rm -f "${NEWROOT}/etc/resolv.conf"
|
|
|
|
cat "${OLDROOT}/etc/resolv.conf" > "${NEWROOT}/etc/resolv.conf"
|
|
|
|
install -DTm0600 <(cat "$PUBKEY") "${NEWROOT}/root/.ssh/authorized_keys"
|
|
|
|
chmod 0700 "${NEWROOT}/root/.ssh"
|
|
|
|
sync && sync # why sync twice? idk
|
|
|
|
|
|
|
|
echo "Swapping rootfs..."
|
|
|
|
# prepare future mount point for our old rootfs
|
|
|
|
mkdir -p "${WORKDIR}/newroot/mnt/oldroot"
|
|
|
|
mount --make-rprivate /
|
|
|
|
|
|
|
|
# swap root
|
|
|
|
pivot_root "${WORKDIR}/newroot" "${WORKDIR}/newroot/mnt/oldroot"
|
|
|
|
|
|
|
|
OLDROOT="/mnt/oldroot"
|
|
|
|
NEWROOT="/"
|
|
|
|
|
|
|
|
# move mounts
|
|
|
|
for i in dev proc sys run; do
|
|
|
|
if [ -d "${OLDROOT}/$i" ]; then
|
|
|
|
mount --move "${OLDROOT}/$i" "${NEWROOT}/$i"
|
2019-04-09 16:59:41 +08:00
|
|
|
fi
|
2019-08-24 14:42:32 +08:00
|
|
|
done
|
2022-11-25 22:31:34 +08:00
|
|
|
mount -t tmpfs -o size=100% tmpfs "${NEWROOT}/tmp"
|
2019-08-24 14:42:32 +08:00
|
|
|
|
2022-11-25 22:31:34 +08:00
|
|
|
mkdir -p "${WORKDIR}"
|
|
|
|
mount --move "${OLDROOT}/${WORKDIR}" "${WORKDIR}"
|
2019-04-09 18:17:53 +08:00
|
|
|
|
2022-11-25 22:31:34 +08:00
|
|
|
echo "Restarting SSH daemon..."
|
|
|
|
systemctl daemon-reload
|
2022-12-01 15:56:15 +08:00
|
|
|
systemctl is-active ssh && systemctl stop ssh || true
|
2022-11-25 22:31:34 +08:00
|
|
|
systemctl restart sshd
|
2019-04-09 15:51:15 +08:00
|
|
|
|
2022-11-25 22:31:34 +08:00
|
|
|
echo "Disabling swap..."
|
|
|
|
swapoff -a
|
2019-04-09 15:51:15 +08:00
|
|
|
|
2022-11-25 22:31:34 +08:00
|
|
|
echo "Restarting init process..."
|
|
|
|
systemctl daemon-reexec
|
2019-04-09 15:51:15 +08:00
|
|
|
|
2022-11-25 22:31:34 +08:00
|
|
|
systemctl --quiet is-system-running || true
|
2019-04-09 15:51:15 +08:00
|
|
|
|
2019-04-10 10:01:22 +08:00
|
|
|
echo -e "If you are connecting from SSH, please create a second session to this host use root and"
|
|
|
|
echo -e "confirm you can get a shell."
|
2019-04-09 15:51:15 +08:00
|
|
|
echo -e "After your confirmation, we are going to kill the old SSH server."
|
|
|
|
|
2022-11-25 22:31:34 +08:00
|
|
|
if menhera::confirm; then
|
|
|
|
echo "Killing all programs still using the old root..."
|
|
|
|
fuser -kvm "${OLDROOT}" -15
|
|
|
|
# in most cases the parent process of this script will be killed, so goodbye
|
2019-04-10 10:01:22 +08:00
|
|
|
else
|
|
|
|
echo -e "Please manually issue a reboot to recover your old OS. If you believe there is a bug in menhera.sh, "
|
|
|
|
echo -e "raise a ticket at https://github.com/Jamesits/menhera.sh/issues ."
|
|
|
|
fi
|