Last active
November 17, 2022 14:43
-
-
Save AlexTMjugador/04c9460ec7a531d8c458038d3e0fa0d1 to your computer and use it in GitHub Desktop.
Script to download and reinstall all the files within a subtree provided by the Debian packages installed on the system. Unlike reinstalling all the packages, this script only extracts the files within the specified subtree, does not execute any package setup scripts, and stores its results in a configurable directory, making it a better fit for…
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 -e | |
# Script to download and reinstall all the files within a subtree | |
# provided by the Debian packages installed on the system. Unlike | |
# reinstalling all the packages, this script only extracts the | |
# files within the specified subtree, does not execute any package | |
# setup scripts, and stores its results in a configurable $OUTPUT_DIR, | |
# making it a better fit for advanced Linux installation repairs. | |
# | |
# When the filesystem to repair does not match the root filesystem | |
# (i.e., it is not mounted at /), the following commands can be used | |
# to run this script as if the filesystem to repair was the root | |
# filesystem. This should work as long as the basic binaries and shared | |
# libraries used by this script were not damaged: | |
# # cd <mountpoint> | |
# # mount -t proc proc proc | |
# # mount -t sysfs sysfs sys | |
# # mount -t devtmpfs devtmpfs dev | |
# # mount -t tmpfs tmpfs tmp | |
# # mount -t tmpfs tmpfs run | |
# <mount other filesystems as needed (/boot, etc.)> | |
# # chroot . | |
# | |
# Although an attempt is made to handle extended attributes properly, | |
# it may happen that some of them are not properly set after this script | |
# completes. It's a good idea to update the system packages or reinstall | |
# them afterwards. Related StackExchange question: | |
# https://askubuntu.com/questions/1099381/fix-setuid-and-setgid-bits-in-usr | |
if [ "$(id -u)" -ne 0 ]; then | |
echo "! This script should be run as root." >&2 | |
exit 1 | |
fi | |
readonly TO_REPAIR_DIR='/usr/bin' | |
readonly OUTPUT_DIR="$PWD/repaired" | |
WORKDIR=$(mktemp -d '/tmp/pkgs.XXX') | |
readonly WORKDIR | |
cleanup() { | |
rm -rf "$WORKDIR" | |
} | |
trap 'cleanup' EXIT INT QUIT TERM | |
# Uncomment the following to extract several packages in parallel. | |
# This may provide nice speedups, at the cost of garbled output. | |
# NOT TESTED. | |
#BATCH_SIZE=$(nproc) | |
BATCH_SIZE=1 | |
readonly BATCH_SIZE | |
copyPackageSubtree() { | |
echo "> Copying package subtree for $1..." | |
apt-get download "$1" | |
# Ignore tar extraction errors, most likely caused by the package | |
# not containing any file in the subtree to be repaired | |
dpkg-deb --fsys-tarfile "${1%%:*}"*.deb | \ | |
{ tar -vx -C "$OUTPUT_DIR" --keep-directory-symlink --overwrite --acls --xattrs \ | |
--wildcards ."$TO_REPAIR_DIR"/'*' || true; } | |
} | |
getInstalledPackages() { | |
dpkg-query --show --showformat='${db:Status-Abbrev}\t${binary:Package}\n' '*' | \ | |
while read -r package_data; do | |
package_status="${package_data%% *}" | |
package_name_and_version="${package_data#* }" | |
if [ "$package_status" = 'ii ' ]; then | |
echo "$package_name_and_version" | |
fi | |
done | |
} | |
cd "$WORKDIR" | |
mkdir -p "$OUTPUT_DIR" | |
remaining_batch_packages=$BATCH_SIZE | |
getInstalledPackages | while read -r package; do | |
if [ "$remaining_batch_packages" -ne 0 ]; then | |
# Extract several packages in parallel to improve performance | |
copyPackageSubtree "$package" & | |
remaining_batch_packages=$((remaining_batch_packages - 1)) | |
else | |
wait | |
remaining_batch_packages=$BATCH_SIZE | |
fi | |
done | |
wait | |
echo "Done! Subtree stored at $OUTPUT_DIR" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment