|
1 | 1 | #!/bin/sh |
| 2 | +# Detect runtime Debian packages for /usr/local Python like python:3.x-slim |
2 | 3 |
|
3 | 4 | set -eu |
4 | 5 |
|
5 | | -VER="$1" |
| 6 | +# Ensure required tools exist (quietly install if needed) |
| 7 | +if ! command -v ldd >/dev/null 2>&1 || ! command -v find >/dev/null 2>&1 || ! command -v dpkg-query >/dev/null 2>&1; then |
| 8 | + export DEBIAN_FRONTEND=noninteractive |
| 9 | + apt-get update 1>&2 |
| 10 | + apt-get install -y --no-install-recommends findutils libc-bin dpkg 1>&2 |
| 11 | +fi |
6 | 12 |
|
7 | | -export DEBIAN_FRONTEND=noninteractive |
8 | | -apt-get update 1>&2 |
9 | | -apt-get install -o APT::Keep-Downloaded-Packages="false" -y --no-install-recommends binutils dpkg findutils libc-bin 1>&2 |
| 13 | +# Collect targets under /usr/local: executables + .so files; skip Tkinter |
| 14 | +targets="$( |
| 15 | + find /usr/local -type f \( -perm -111 -o -name '*.so' -o -name '*.so.*' \) \ |
| 16 | + ! -name '*tkinter*' -print 2>/dev/null || true |
| 17 | +)" |
10 | 18 |
|
11 | | -# build scan list only from existing files |
12 | | -scan_paths="" |
13 | | -for p in /usr/local/bin/python3 \ |
14 | | - /usr/local/lib/libpython*.so* \ |
15 | | - /usr/local/lib/python*/lib-dynload/*.so; do |
16 | | - [ -e "$p" ] && scan_paths="$scan_paths $p" |
17 | | -done |
| 19 | +# If nothing to scan, still print the three base runtime packages and exit |
| 20 | +if [ -z "${targets}" ]; then |
| 21 | + printf '%s\n' ca-certificates netbase tzdata |
| 22 | + exit 0 |
| 23 | +fi |
18 | 24 |
|
19 | | -# DT_NEEDED sonames (no execution) |
20 | | -neededs=$( |
21 | | - objdump -p $scan_paths 2>/dev/null | awk '/^ NEEDED /{print $2}' | sort -u |
22 | | -) |
| 25 | +# Resolve full transitive shared libs via ldd, drop /usr/local and linux-vdso |
| 26 | +so_paths="$( |
| 27 | + printf '%s\n' "$targets" \ |
| 28 | + | xargs -r ldd 2>/dev/null \ |
| 29 | + | awk ' |
| 30 | + # Typical: "libX.so => /path/libX.so (0x...)" |
| 31 | + /=>/ && $3 ~ /^\// { print $3; next } |
| 32 | + # Also: " /path/libY.so (0x...)" (no "=>") |
| 33 | + /^[[:space:]]*\// { print $1 } |
| 34 | + ' \ |
| 35 | + | grep -v '^/usr/local/' \ |
| 36 | + | grep -v 'linux-vdso' \ |
| 37 | + | sort -u |
| 38 | +)" |
23 | 39 |
|
24 | | -# Resolve SONAMEs to real files by scanning common lib dirs |
25 | | -so_files=$( |
26 | | - for so in $neededs; do |
27 | | - for d in \ |
28 | | - /lib/*-linux-gnu /usr/lib/*-linux-gnu \ |
29 | | - /lib /usr/lib; do |
30 | | - f="$d/$so" |
31 | | - [ -e "$f" ] && printf '%s\n' "$f" |
32 | | - done |
33 | | - done | sort -u |
34 | | -) |
| 40 | +# Map each real path to a package (keep :arch suffix), dedupe |
| 41 | +pkgs="$( |
| 42 | + printf '%s\n' "$so_paths" \ |
| 43 | + | sed -E 's#^/(usr/)?##' \ |
| 44 | + | sed 's#^#*#' \ |
| 45 | + | xargs -r dpkg-query --search 2>/dev/null \ |
| 46 | + | awk 'sub(":$", "", $1) { print $1 }' \ |
| 47 | + | sort -u |
| 48 | +)" |
35 | 49 |
|
36 | | -# Map files -> packages |
37 | | -printf '%s\n' $so_files | xargs -r dpkg -S | cut -d: -f1 | sort -u |
| 50 | +# Output packages + the non-ELF runtime packages the scan can’t “see” |
| 51 | +printf '%s\n' "$pkgs" |
| 52 | +printf '%s\n' ca-certificates netbase tzdata |
0 commit comments