diff --git a/menhera.sh b/menhera.sh index 6967d66..4f3ff38 100755 --- a/menhera.sh +++ b/menhera.sh @@ -3,69 +3,25 @@ set -Eeuo pipefail # disable command path hashing as we are going to move fast and break things set +h -# config WORKDIR="/tmp/menhera" MIRROR="https://iso.meson.cc/ultralite/archlinux" ROOTFS="${MIRROR}/iso/latest/arch/x86_64/airootfs.sfs" -declare -A ARCH_MAP=( - ["x86_64"]="amd64" -) - # internal global variables OLDROOT="/" NEWROOT="" -MACHINE_TYPE=$(uname -m) -ARCH_ID=${ARCH_MAP[$MACHINE_TYPE]:-$MACHINE_TYPE} +[[ "$(uname -m)" == "x86_64" ]] || { echo "error: wrong arch $(uname -m) (not x86_64)"; exit 1; } -# fix possible PATH problems -export PATH="$PATH:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" +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; } -menhera::reset_sshd_config() { - cat > /etc/ssh/sshd_config <&2 - exit 1 - fi -} - -menhera::__compat_reload_init() { - if [ -x "$(command -v systemctl)" ]; then - systemctl daemon-reexec - elif [ -x "$(command -v telinit)" ]; then - telinit u - else - echo "ERROR: Cannot re-exec init, init system not recognized" >&2 - exit 1 - fi -} +systemctl status > /dev/null || { echo "error: no systemd"; exit 1; } # helper functions # https://stackoverflow.com/a/3232082/2646069 @@ -73,7 +29,7 @@ menhera::confirm() { # call with a prompt string or use a default read -r -p "${1:-Are you sure? [y/N]} " response case "$response" in - [yY][eE][sS]|[yY]) + [yY][eE][sS]|[yY]) true ;; *) @@ -82,160 +38,6 @@ menhera::confirm() { esac } -# jobs -menhera::get_rootfs() { - if [ -z "${ROOTFS}" ]; then - echo "Getting rootfs URL..." - - # forgive me for parsing HTML with these shit - # and hope it works - ROOTFS_TIME=$(wget -qO- --show-progress "https://images.linuxcontainers.org/images/debian/buster/${ARCH_ID}/default/?C=M;O=D" | grep -oP '(\d{8}_\d{2}:\d{2})' | head -n 1) - - ROOTFS="https://images.linuxcontainers.org/images/debian/buster/${ARCH_ID}/default/${ROOTFS_TIME}/rootfs.squashfs" - else - echo "\$ROOTFS is set to '$ROOTFS'" - fi -} - -menhera::sync_filesystem() { - echo "Syncing..." - sync - sync -} - -menhera::prepare_environment() { - 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}" - - # new rootfs - mkdir -p "${WORKDIR}/newroot" - # readonly part of new rootfs - mkdir -p "${WORKDIR}/newrootro" - # writeable part of new rootfs - mkdir -p "${WORKDIR}/newrootrw" - # overlayfs workdir - mkdir -p "${WORKDIR}/overlayfs_workdir" - - echo "Downloading temporary rootfs..." - wget -q --show-progress -O "${WORKDIR}/rootfs.squashfs" "${ROOTFS}" -} - -menhera::mount_new_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" -} - -menhera::install_software() { - return - echo "Installing OpenSSH Server into new rootfs..." - - # disable APT cache - echo -e 'Dir::Cache "";\nDir::Cache::archives "";' > "${NEWROOT}/etc/apt/apt.conf.d/00_disable-cache-directories" - - DEBIAN_FRONTEND=noninteractive chroot "${NEWROOT}" apt-get update -y - DEBIAN_FRONTEND=noninteractive chroot "${NEWROOT}" apt-get -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" install -y openssh-server -} - -menhera::copy_config() { - echo "Copying important config into new rootfs..." - ! cp -axL "${OLDROOT}/etc/resolv.conf" "${NEWROOT}/etc" - ! cp -axr "${OLDROOT}/etc/ssh" "${NEWROOT}/etc" - ! cp -ax "${OLDROOT}/etc/"{passwd,shadow} "${NEWROOT}/etc" - ! cp -axr "${OLDROOT}/root/.ssh" "${NEWROOT}/root" - - chroot "${NEWROOT}" chsh -s /bin/bash root - - cat > "${NEWROOT}/etc/motd" < "${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" + fi +done +mount -t tmpfs -o size=100% tmpfs "${NEWROOT}/tmp" + +mkdir -p "${WORKDIR}" +mount --move "${OLDROOT}/${WORKDIR}" "${WORKDIR}" + +echo "Restarting SSH daemon..." +systemctl daemon-reload +systemctl restart sshd + +echo "Disabling swap..." +swapoff -a + +echo "Restarting init process..." +systemctl daemon-reexec + +systemctl --quiet is-system-running || true 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." echo -e "After your confirmation, we are going to kill the old SSH server." -if menhera::confirm; then - menhera::clear_processes +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 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 ." - exit 1 fi