snap-mgmt 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. #!/bin/bash
  2. # Overlord management of snapd for package manager actions.
  3. # Implements actions that would be invoked in %pre(un) actions for snapd.
  4. # Derived from the snapd.postrm scriptlet used in the Ubuntu packaging for
  5. # snapd.
  6. set -e
  7. set +x
  8. SNAP_MOUNT_DIR="/snap"
  9. show_help() {
  10. exec cat <<'EOF'
  11. Usage: snap-mgmt.sh [OPTIONS]
  12. A simple script to cleanup snap installations.
  13. optional arguments:
  14. --help Show this help message and exit
  15. --snap-mount-dir=<path> Provide a path to be used as $SNAP_MOUNT_DIR
  16. --purge Purge all data from $SNAP_MOUNT_DIR
  17. EOF
  18. }
  19. SNAP_UNIT_PREFIX="$(systemd-escape -p ${SNAP_MOUNT_DIR})"
  20. systemctl_stop() {
  21. unit="$1"
  22. if systemctl is-active -q "$unit"; then
  23. echo "Stopping $unit"
  24. systemctl stop -q "$unit" || true
  25. fi
  26. }
  27. purge() {
  28. # shellcheck disable=SC1091
  29. distribution=$(. /etc/os-release; echo "${ID}-${VERSION_ID}")
  30. if [ "$distribution" = "ubuntu-14.04" ]; then
  31. # snap.mount.service is a trusty thing
  32. systemctl_stop snap.mount.service
  33. fi
  34. # Undo any bind mounts to ${SNAP_MOUNT_DIR} or /var/snap done by parallel
  35. # installs or LP:#1668659
  36. for mp in "$SNAP_MOUNT_DIR" /var/snap; do
  37. if grep -q " $mp $mp" /proc/self/mountinfo; then
  38. umount -l "$mp" || true
  39. fi
  40. done
  41. units=$(systemctl list-unit-files --no-legend --full | grep -vF snap.mount.service || true)
  42. # *.snap mount points
  43. mounts=$(echo "$units" | grep "^${SNAP_UNIT_PREFIX}[-.].*\\.mount" | cut -f1 -d ' ')
  44. # services from snaps
  45. services=$(echo "$units" | grep '^snap\..*\.service' | cut -f1 -d ' ')
  46. for unit in $services $mounts; do
  47. # ensure its really a snap mount unit or systemd unit
  48. if ! grep -q 'What=/var/lib/snapd/snaps/' "/etc/systemd/system/$unit" && ! grep -q 'X-Snappy=yes' "/etc/systemd/system/$unit"; then
  49. echo "Skipping non-snapd systemd unit $unit"
  50. continue
  51. fi
  52. echo "Stopping $unit"
  53. systemctl_stop "$unit"
  54. if echo "$unit" | grep -q '.*\.mount' ; then
  55. # Transform ${SNAP_MOUNT_DIR}/core/3440 -> core/3440 removing any
  56. # extra / preceding snap name, eg:
  57. # /var/lib/snapd/snap/core/3440 -> core/3440
  58. # /snap/core/3440 -> core/3440
  59. # /snap/core//3440 -> core/3440
  60. # NOTE: we could have used `systemctl show $unit -p Where --value`
  61. # but systemd 204 shipped with Ubuntu 14.04 does not support this
  62. snap_rev=$(systemctl show "$unit" -p Where | sed -e 's#Where=##' -e "s#$SNAP_MOUNT_DIR##" -e 's#^/*##')
  63. snap=$(echo "$snap_rev" |cut -f1 -d/)
  64. rev=$(echo "$snap_rev" |cut -f2 -d/)
  65. if [ -n "$snap" ]; then
  66. echo "Removing snap $snap"
  67. # aliases
  68. if [ -d "${SNAP_MOUNT_DIR}/bin" ]; then
  69. find "${SNAP_MOUNT_DIR}/bin" -maxdepth 1 -lname "$snap" -delete
  70. find "${SNAP_MOUNT_DIR}/bin" -maxdepth 1 -lname "$snap.*" -delete
  71. fi
  72. # generated binaries
  73. rm -f "${SNAP_MOUNT_DIR}/bin/$snap"
  74. rm -f "${SNAP_MOUNT_DIR}/bin/$snap".*
  75. # snap mount dir
  76. umount -l "${SNAP_MOUNT_DIR}/$snap/$rev" 2> /dev/null || true
  77. rm -rf "${SNAP_MOUNT_DIR:?}/$snap/$rev"
  78. rm -f "${SNAP_MOUNT_DIR}/$snap/current"
  79. # snap data dir
  80. rm -rf "/var/snap/$snap/$rev"
  81. rm -rf "/var/snap/$snap/common"
  82. rm -f "/var/snap/$snap/current"
  83. # opportunistic remove (may fail if there are still revisions left)
  84. for d in "${SNAP_MOUNT_DIR}/$snap" "/var/snap/$snap"; do
  85. if [ -d "$d" ]; then
  86. rmdir --ignore-fail-on-non-empty "$d"
  87. fi
  88. done
  89. # udev rules
  90. find /etc/udev/rules.d -name "*-snap.${snap}.rules" -execdir rm -f "{}" \;
  91. # dbus policy files
  92. if [ -d /etc/dbus-1/system.d ]; then
  93. find /etc/dbus-1/system.d -name "snap.${snap}.*.conf" -execdir rm -f "{}" \;
  94. fi
  95. # timer and socket units
  96. find /etc/systemd/system -name "snap.${snap}.*.timer" -o -name "snap.${snap}.*.socket" | while read -r f; do
  97. systemctl_stop "$(basename "$f")"
  98. rm -f "$f"
  99. done
  100. fi
  101. fi
  102. echo "Removing $unit"
  103. rm -f "/etc/systemd/system/$unit"
  104. rm -f "/etc/systemd/system/multi-user.target.wants/$unit"
  105. done
  106. echo "Discarding preserved snap namespaces"
  107. # opportunistic as those might not be actually mounted
  108. if [ -d /run/snapd/ns ]; then
  109. if [ "$(find /run/snapd/ns/ -name "*.mnt" | wc -l)" -gt 0 ]; then
  110. for mnt in /run/snapd/ns/*.mnt; do
  111. umount -l "$mnt" || true
  112. rm -f "$mnt"
  113. done
  114. fi
  115. find /run/snapd/ns/ \( -name '*.fstab' -o -name '*.user-fstab' -o -name '*.info' \) -delete
  116. umount -l /run/snapd/ns/ || true
  117. fi
  118. echo "Removing downloaded snaps"
  119. rm -rf /var/lib/snapd/snaps/*
  120. echo "Removing features exported from snapd to helper tools"
  121. rm -rf /var/lib/snapd/features
  122. echo "Final directory cleanup"
  123. rm -rf "${SNAP_MOUNT_DIR}"
  124. rm -rf /var/snap
  125. echo "Removing leftover snap shared state data"
  126. rm -rf /var/lib/snapd/desktop/applications/*
  127. rm -rf /var/lib/snapd/seccomp/bpf/*
  128. rm -rf /var/lib/snapd/device/*
  129. rm -rf /var/lib/snapd/assertions/*
  130. rm -rf /var/lib/snapd/cookie/*
  131. rm -rf /var/lib/snapd/cache/*
  132. rm -rf /var/lib/snapd/mount/*
  133. rm -rf /var/lib/snapd/sequence/*
  134. rm -rf /var/lib/snapd/apparmor/*
  135. rm -f /var/lib/snapd/state.json
  136. rm -f /var/lib/snapd/system-key
  137. echo "Removing snapd catalog cache"
  138. rm -rf /var/cache/snapd/*
  139. if test -d /etc/apparmor.d; then
  140. # Remove auto-generated rules for snap-confine from the 'core' snap
  141. echo "Removing extra snap-confine apparmor rules"
  142. # shellcheck disable=SC2046
  143. rm -f /etc/apparmor.d/$(echo "$SNAP_UNIT_PREFIX" | tr '-' '.').core.*.usr.lib.snapd.snap-confine
  144. fi
  145. }
  146. while [ -n "$1" ]; do
  147. case "$1" in
  148. --help)
  149. show_help
  150. exit
  151. ;;
  152. --snap-mount-dir=*)
  153. SNAP_MOUNT_DIR=${1#*=}
  154. SNAP_UNIT_PREFIX=$(systemd-escape -p "$SNAP_MOUNT_DIR")
  155. shift
  156. ;;
  157. --purge)
  158. purge
  159. shift
  160. ;;
  161. *)
  162. echo "Unknown command: $1"
  163. exit 1
  164. ;;
  165. esac
  166. done