Skip to content

Commit

Permalink
Make uninstall way more fault tolerant, and report better errors
Browse files Browse the repository at this point in the history
  • Loading branch information
Eeems committed Jun 2, 2024
1 parent fcedcd4 commit 2645de9
Showing 1 changed file with 94 additions and 27 deletions.
121 changes: 94 additions & 27 deletions package/toltec-bootstrap/toltecctl
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@

set -euo pipefail

# Path to this script
toltecctl_path=$(realpath "$0")

# Path where Toltec resides (will be mounted to $toltec_dest)
toltec_src=/home/root/.entware

Expand All @@ -15,7 +18,7 @@ toltec_share=/home/root/.local/share/toltec
# Path to static opkg build
opkg_path=/home/root/.local/bin/opkg
# Path to opkg install status file
opkg_status="/opt/lib/opkg/status"
opkg_status="$toltec_dest/lib/opkg/status"

# Path to Opkg configuration
opkg_conf="$toltec_src"/etc/opkg.conf
Expand Down Expand Up @@ -123,7 +126,7 @@ get-release-version() {
# 3 - unable to install standalone wget
check-version() {
local wget
if [[ "$(install-state)" != "yes" ]] || [[ "$(command -v wget)" != "/opt/bin/wget" ]]; then
if [[ "$(install-state)" != "yes" ]] || [[ "$(command -v wget)" != "$toltec_dest/bin/wget" ]]; then
if ! install-standalone-wget; then
return 2
fi
Expand Down Expand Up @@ -197,9 +200,9 @@ add-bind-mount() {
unit_name="$(basename "$unit_path")"

if [[ -e $unit_path ]]; then
echo "Bind mount configuration for '$2' already exists, updating"
log INFO "Bind mount configuration for '$2' already exists, updating"
else
echo "Mounting '$1' over '$2'"
log INFO "Mounting '$1' over '$2'"
fi

cat > "$unit_path" << UNIT
Expand Down Expand Up @@ -234,11 +237,11 @@ remove-bind-mount() {
unit_name="$(basename "$unit_path")"

if [[ ! -e $unit_path ]]; then
echo "No existing bind mount for '$1'"
log INFO "No existing bind mount for '$1'"
return
fi

echo "Removing mount over '$1'"
log INFO "Removing mount over '$1'"
systemctl disable "$unit_name"
systemctl stop "$unit_name"
if mountpoint -q "$1"; then
Expand Down Expand Up @@ -460,7 +463,7 @@ reinstall-root() {
if [[ -v "on_root_packages[$pkgname]" ]]; then
reinstall_packages[$pkgname]=1
fi
done < <(gunzip -c /opt/var/opkg-lists/* | grep "^Package:" | awk '{print $2}')
done < <(gunzip -c $toltec_dest/var/opkg-lists/* | grep "^Package:" | awk '{print $2}')

# Workaround: Checking the size of an empty array when the nounset option
# is active may throw an error on some Bash versions, so we disable it
Expand All @@ -480,6 +483,7 @@ clean-path() {
sed -i "/^$bashrc_start_marker\$/,/^$bashrc_end_marker\$/d" "$bashrc_path"
sed -i "/^$bashrc_old_start_marker\$/!b;n;d" "$bashrc_path"
sed -i "/^$bashrc_old_start_marker\$/d" "$bashrc_path"
# TODO - rewrite this to use $toltec_dest instead of /opt
sed -i '/^\(export \)\?PATH="\?\.*\/opt\/bin:\/opt\/sbin.*"\?$/d' "$bashrc_path"
fi
}
Expand All @@ -492,7 +496,7 @@ set-path() {
clean-path
cat >> "$bashrc_path" << SHELL
$bashrc_start_marker
PATH="/opt/bin:/opt/sbin:/home/root/.local/bin:\$PATH"
PATH="$toltec_dest/bin:$toltec_dest/sbin:/home/root/.local/bin:\$PATH"
$bashrc_end_marker
SHELL

Expand Down Expand Up @@ -541,9 +545,9 @@ generate-opkg-conf() {
# then run \`toltecctl generate-opkg-conf\` to regenerate this file
dest root /
dest ram /opt/tmp
lists_dir ext /opt/var/opkg-lists
option tmp_dir /opt/tmp
dest ram $toltec_dest/tmp
lists_dir ext $toltec_dest/var/opkg-lists
option tmp_dir $toltec_dest/tmp
CONF

Expand Down Expand Up @@ -672,23 +676,23 @@ CONF

# Re-enable Toltec install after system update
reenable() {
log INFO "Mounting /opt"
log INFO "Mounting $toltec_dest"
add-bind-mount "$toltec_src" "$toltec_dest"
switch-branch "$(get-branch)"
log INFO "Generating /opt/etc/opkg.conf"
log INFO "Generating $toltec_dest/etc/opkg.conf"
generate-opkg-conf || true
log INFO "Opkg update"
opkg update
log INFO "Reinsalling base packages"
reinstall-base
log INFO "Reinstalling packages with files on the root partition"
reinstall-root
if [ -d /opt/share/toltec/reenable.d ]; then
find /opt/share/toltec/reenable.d -maxdepth 1 -mindepth 1 -print0 \
if [ -d $toltec_dest/share/toltec/reenable.d ]; then
find $toltec_dest/share/toltec/reenable.d -maxdepth 1 -mindepth 1 -print0 \
| xargs -0rn1 basename \
| while read -r pkg; do
local script
script="/opt/lib/opkg/info/${pkg}.postinst"
script="$toltec_dest/lib/opkg/info/${pkg}.postinst"
if [ -f "$script" ]; then
log INFO "Reconfiguring ${pkg}"
"$script" configure || true
Expand Down Expand Up @@ -720,7 +724,7 @@ list-installed-ordered() {
# Install standalone opkg binary
install-standalone-opkg() {
local wget
if [[ "$(install-state)" != "yes" ]] || [[ "$(command -v wget)" != "/opt/bin/wget" ]]; then
if [[ "$(install-state)" != "yes" ]] || [[ "$(command -v wget)" != "$toltec_dest/bin/wget" ]]; then
if ! install-standalone-wget; then
return 2
fi
Expand Down Expand Up @@ -775,12 +779,49 @@ install-standalone-wget() {

# Remove Toltec completely
uninstall() {
if ! [ -d "$toltec_src" ] && ! [ -d "$toltec_dest" ]; then
log INFO "Toltec does not appear to be installed"
exit 0
fi

# Fetch standalone opkg used to uninstall packages
if ! install-standalone-opkg; then
return 1
fi

local clean=true
local success=true

broken-state() {
echo " Your system may be in a broken state. Please review the logs"
echo " before rebooting your device. If you need assistance, you can"
echo " get help on the community discord channel."
}

cleanup() {
local error_code=$?
log ERROR "$BASH_LINENO: $BASH_COMMAND"
log ERROR "Uninstall did not complete properly"
broken-state
exit $error_code
}
trap cleanup ERR

if [[ "$toltecctl_path" != *_backup ]]; then
log INFO "Creating backup of toltecctl at ${toltecctl_path}_backup"
rm -f "${toltecctl_path}_backup"
cp "$toltecctl_path" "${toltecctl_path}_backup"
fi

if ! [ -f "$toltec_dest"/etc/opkg.conf ]; then
if [ -f "$toltec_src"/etc/opkg.conf ] && ! mountpoint -q "$toltec_dest"; then
log INFO "Mounting $toltec_dest"
add-bind-mount "$toltec_src" "$toltec_dest"
fi
log ERROR "Current install seems to be partially removed, unable to automatically removed."
broken-state
exit 1
fi

# Remove installed packages in reverse dependency order
while read -r pkgname; do
if ! "$opkg_path" remove --force-depends "$pkgname"; then
Expand All @@ -792,28 +833,54 @@ uninstall() {
$(list-installed-ordered)
EOF

systemctl daemon-reload
if ! systemctl daemon-reload; then
log WARN "Failed to reload systemd state"
fi
rm -f "$opkg_path"

# Remove mount point
remove-bind-mount "$toltec_dest"
rmdir "$toltec_dest"

case "$(install-state)" in
no) ;;
*)
log ERROR "$toltec_dest bind mount still is active"
success=false
;;
esac

if ! rmdir "$toltec_dest"; then
log ERROR "Failed to remove mount point"
success=false
fi

# Unset PATH
clean-path

# Remove Toltec data
rm -r "$toltec_src"
if ! rm -r "$toltec_src"; then
log ERROR "Failed to remove toltec data directory"
success=false
fi

# Re-enable xochitl if needed
systemctl enable xochitl

if ! systemctl enable xochitl; then
log ERROR "Failed to enable the user interface."
success=false
fi
if ! $clean; then
echo "Warning: There were errors removing some of the toltec packages."
echo " Your system may be in a broken state. Please review the logs"
echo " before rebooting your device. If you need assistance, you can"
echo " get help on the community discord channel."
log ERROR "There were errors removing some of the toltec packages."
success=false
fi
if ! $success; then
log ERROR "Uninstall failed"
broken-state
exit 1
fi
if [[ "$toltecctl_path" != *_backup ]]; then
rm -f "$toltecctl_path"
fi
rm -f "${toltecctl_path}_backup"
}

# The current toltec install state
Expand Down

0 comments on commit 2645de9

Please sign in to comment.