Last active
October 7, 2025 19:08
-
-
Save dotysan/520a48851368751de642dbc8136caecd to your computer and use it in GitHub Desktop.
Scan *all* debian image tags from Docker Hub and report which ones result in `ldd /usr/bin/mc` showing a broken libcom_err.so.2 after installing mc.
This file contains hidden or 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
| #!/usr/bin/env bash | |
| # | |
| # find-mc-libcomerr-bug.sh | |
| # Scan *all* debian image tags from Docker Hub and report | |
| # which ones result in `ldd /usr/bin/mc` showing a broken libcom_err.so.2 | |
| # after installing mc. | |
| IMAGE_REPO='library/debian' | |
| PAGE_SIZE=100 # API max page size | |
| REPO_API='https://registry.hub.docker.com/v2/repositories' | |
| TMP_DIR="$(mktemp -d)" | |
| trap 'rm --force --recursive -- "$TMP_DIR"' EXIT | |
| declare -a TAGS BAD_TAGS | |
| GOOD_TAG='' BAD_TAG='' | |
| #DEBUG=yep | |
| main() { | |
| # set +x | |
| # fetch_and_filter_tags '1 year' | |
| fetch_and_filter_tags '9 months' | |
| # fetch_and_filter_tags '6 months' | |
| # fetch_and_filter_tags '2 months' | |
| # set -x | |
| scan_all_tags | |
| # bisect_tags | |
| report_results | |
| } | |
| ################################################################################ | |
| fetch_and_filter_tags() { | |
| local ago="$1" | |
| echo "๐ฅ Fetching debian image tags..." | |
| local cutoff=$(date -d "$ago ago" +%Y%m%d) | |
| local json | |
| local page=1 | |
| while : | |
| do | |
| json=$(get_page "$page") | |
| jq -r '.results[].name' <<<"$json" >>"$TMP_DIR/tags.raw" | |
| if jq -e '.next == null' <<<"$json" >/dev/null | |
| then break | |
| fi | |
| ((page++)) | |
| done | |
| awk -F'-' -v cutoff="$cutoff" ' | |
| # all slim images with datestamps | |
| /^[a-z]+-[0-9]{8}-slim$/ { | |
| # /^sid-[0-9]{8}-slim$/ { | |
| # /^[a-z]+-202502..-slim$/ { | |
| # # June 2025 only | |
| # /^[a-z]+-202506..$/ { | |
| date = $2 | |
| if (date >= cutoff) | |
| printf "%s-%s\n", date, $0 | |
| } | |
| ' "$TMP_DIR/tags.raw" | | |
| sort | | |
| cut -d'-' -f2- >"$TMP_DIR/tags.sorted" | |
| # cat "$TMP_DIR/tags.sorted" | |
| mapfile -t TAGS <"$TMP_DIR/tags.sorted" | |
| echo "๐งฎ Filtered, date-sorted tags: ${#TAGS[@]}" | |
| } | |
| get_page() { | |
| local page="$1" | |
| curl -sSL "$REPO_API/$IMAGE_REPO/tags?page_size=$PAGE_SIZE&page=$page" | |
| } | |
| scan_all_tags() { | |
| for tag in "${TAGS[@]}" | |
| do | |
| if ! has_bug "$tag" | |
| then BAD_TAG="$tag" | |
| else GOOD_TAG="$tag" | |
| fi | |
| done | |
| } | |
| has_bug() { | |
| local tag="$1" | |
| echo -n "๐งช Testing debian:$tag ... " | |
| if docker run --rm -i "debian:$tag" bash <<-EOF | |
| set -e | |
| export DEBIAN_FRONTEND=noninteractive | |
| apt-get -qq update | |
| apt-get -qq install -y mc --no-install-recommends &>/dev/null | |
| ldd /usr/bin/mc |grep -q 'libcom_err\.so\.2 => not found' | |
| EOF | |
| then | |
| echo "โ bug present" | |
| BAD_TAGS+=("$tag") | |
| return 1 | |
| else | |
| echo "โ OK" | |
| return 0 | |
| fi | |
| } | |
| todo_bisect_tags() { | |
| local lo=0 hi=$(( ${#TAGS[@]} - 1 )) mid | |
| while (( lo <= hi )) | |
| do | |
| mid=$(( (lo + hi) / 2 )) | |
| local tag="${TAGS[mid]}" | |
| if ! has_bug "$tag" | |
| then | |
| BAD_TAG="$tag" | |
| hi=$(( mid - 1 )) | |
| else | |
| GOOD_TAG="$tag" | |
| lo=$(( mid + 1 )) | |
| fi | |
| done | |
| } | |
| report_results() { | |
| echo | |
| if (( ${#BAD_TAGS[@]} == 0 )) | |
| then | |
| echo "๐ No affected images found." | |
| else | |
| echo "๐จ Affected Debian tags where 'mc' has broken libcom_err.so.2:" | |
| printf '%s\n' "${BAD_TAGS[@]}" | |
| fi | |
| } | |
| todo_wtf() { | |
| if [[ -n "$BAD_TAG" ]] | |
| then | |
| echo "โ First bad tag : $BAD_TAG" | |
| if [[ -n "$GOOD_TAG" ]] | |
| then | |
| echo "โ Last known good: $GOOD_TAG" | |
| else | |
| echo "โ No good tag found before regression." | |
| fi | |
| list_affected_from_bad | |
| else | |
| echo "๐ No affected tags found." | |
| fi | |
| } | |
| list_affected_from_bad() { | |
| echo | |
| echo "๐จ All affected slim tags from '$BAD_TAG' onward:" | |
| local print=0 | |
| for tag in "${TAGS[@]}"; do | |
| if [[ "$tag" == "$BAD_TAG" ]]; then print=1; fi | |
| if (( print )); then echo "$tag"; fi | |
| done | |
| } | |
| #======================================================================= | |
| if [ -z "${BASH_VERSINFO[0]}" ] || [ ${BASH_VERSINFO[0]} -lt 4 ] | |
| then | |
| echo "ERROR: Only tested on Bourne-Again SHell v4/v5." | |
| exit 1 | |
| fi >&2 | |
| # poor man's __main__ | |
| return 2>/dev/null ||: | |
| if [ "$(type -t "$1")" = "function" ] | |
| then | |
| func="$1" | |
| shift 1 | |
| $func "$@" | |
| exit 0 | |
| fi | |
| set -o errexit | |
| set -o nounset | |
| set -o pipefail | |
| if [[ "${DEBUG:-}" ]] | |
| then | |
| PS4func() { | |
| local lineno="$1" | |
| if [[ $lineno == 1 ]] | |
| then lineno=0 | |
| fi | |
| local src d | |
| if [[ ${BASH_SOURCE[0]} == main ]] | |
| then | |
| src='<stdin>' | |
| d=$((${#FUNCNAME[@]}-1)) | |
| else | |
| src="${BASH_SOURCE[0]##*/}" | |
| d=$((${#FUNCNAME[@]}-2)) | |
| fi | |
| local i f='' | |
| for ((i=d; i>0; i--)) | |
| do f+="${FUNCNAME[i]}()" | |
| done | |
| local c="\033[0;36m" y="\033[0;33m" n="\033[0m" | |
| printf "$y%s:%04d$c%s$n " "$src" "$lineno" "$f" | |
| } | |
| PS4='\r$(PS4func $LINENO)' | |
| set -o xtrace | |
| fi | |
| main "$@" | |
| exit 0 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment